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 float DistributeEvenly_amount;
11 float DistributeEvenly_totalweight;
12 void DistributeEvenly_Init(float amount, float totalweight)
14 if (DistributeEvenly_amount)
16 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
17 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
20 DistributeEvenly_amount = 0;
22 DistributeEvenly_amount = amount;
23 DistributeEvenly_totalweight = totalweight;
25 float DistributeEvenly_Get(float weight)
30 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
31 DistributeEvenly_totalweight -= weight;
32 DistributeEvenly_amount -= f;
36 void move_out_of_solid_expand(entity e, vector by)
39 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
42 if (trace_fraction < 1)
45 // adjust origin in the other direction...
46 setorigin(e,e.origin - by * (1 - trace_fraction));
50 float move_out_of_solid(entity e)
55 traceline(o, o, MOVE_WORLDONLY, e);
59 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
60 if (!trace_startsolid)
67 move_out_of_solid_expand(e, '1 0 0' * m0_x);
69 move_out_of_solid_expand(e, '1 0 0' * m1_x);
71 move_out_of_solid_expand(e, '0 1 0' * m0_y);
73 move_out_of_solid_expand(e, '0 1 0' * m1_y);
75 move_out_of_solid_expand(e, '0 0 1' * m0_z);
77 move_out_of_solid_expand(e, '0 0 1' * m1_z);
79 setorigin(e, e.origin);
81 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
91 string STR_PLAYER = "player";
92 string STR_SPECTATOR = "spectator";
93 string STR_OBSERVER = "observer";
96 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
97 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
98 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
99 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
101 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
102 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
103 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
104 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
105 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
108 // copies a string to a tempstring (so one can strunzone it)
109 string strcat1(string s) = #115; // FRIK_FILE
114 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
116 local float nPlayerHealth = rint(enPlayer.health);
117 local float nPlayerArmor = rint(enPlayer.armorvalue);
118 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
119 local float nPlayerPing = rint(enPlayer.ping);
120 local string strPlayerPingColor;
121 local string strMessage;
122 if(nPlayerPing >= 150)
123 strPlayerPingColor = "^1";
125 strPlayerPingColor = "^2";
127 if((cvar("sv_fragmessage_information_typefrag")) && (enPlayer.classname == "player") && (enPlayer.BUTTON_CHAT))
128 strMessage = strcat(strMessage, " ^1(typefrag)");
129 if((cvar("sv_fragmessage_information_stats")) && (nPlayerHealth >= 1))
130 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
132 if(cvar("sv_fragmessage_information_ping")) {
133 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
134 strMessage = strcat(strMessage, "\n^7(^2Bot");
136 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
137 if(cvar("sv_fragmessage_information_handicap"))
138 if(cvar("sv_fragmessage_information_handicap") == 2)
139 if(nPlayerHandicap <= 1)
140 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
142 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
143 else if not(nPlayerHandicap <= 1)
144 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
146 strMessage = strcat(strMessage, "^7)");
147 } else if(cvar("sv_fragmessage_information_handicap")) {
148 if(cvar("sv_fragmessage_information_handicap") == 2)
149 if(nPlayerHandicap <= 1)
150 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
152 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
153 else if(nPlayerHandicap > 1)
154 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
158 void bcenterprint(string s)
160 // TODO replace by MSG_ALL (would show it to spectators too, though)?
162 FOR_EACH_PLAYER(head)
163 if (clienttype(head) == CLIENTTYPE_REAL)
164 centerprint(head, s);
167 void GameLogEcho(string s)
172 if (cvar("sv_eventlog_files"))
177 matches = cvar("sv_eventlog_files_counter") + 1;
178 cvar_set("sv_eventlog_files_counter", ftos(matches));
181 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
182 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
183 logfile = fopen(fn, FILE_APPEND);
184 fputs(logfile, ":logversion:3\n");
188 if (cvar("sv_eventlog_files_timestamps"))
189 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
191 fputs(logfile, strcat(s, "\n"));
194 if (cvar("sv_eventlog_console"))
203 // will be opened later
208 if (logfile_open && logfile >= 0)
215 float spawnpoint_nag;
216 void relocate_spawnpoint()
218 // nudge off the floor
219 setorigin(self, self.origin + '0 0 1');
221 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
222 if (trace_startsolid)
228 if (!move_out_of_solid(self))
229 objerror("could not get out of solid at all!");
230 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
231 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
232 print(" ", ftos(self.origin_y - o_y));
233 print(" ", ftos(self.origin_z - o_z), "'\n");
234 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
237 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
243 self.mins = self.maxs = '0 0 0';
244 objerror("player spawn point in solid, mapper sucks!\n");
249 if (cvar("g_spawnpoints_autodrop"))
251 setsize(self, PL_MIN, PL_MAX);
255 self.use = spawnpoint_use;
256 self.team_saved = self.team;
260 if (g_ctf || g_assault || g_onslaught || g_domination || g_nexball)
262 have_team_spawns = 1;
264 if (cvar("r_showbboxes"))
266 // show where spawnpoints point at too
267 makevectors(self.angles);
270 e.classname = "info_player_foo";
271 setorigin(e, self.origin + v_forward * 24);
272 setsize(e, '-8 -8 -8', '8 8 8');
273 e.solid = SOLID_TRIGGER;
277 #define strstr strstrofs
279 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
280 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
281 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
282 // BE CONSTANT OR strzoneD!
283 float strstr(string haystack, string needle, float offset)
287 len = strlen(needle);
288 endpos = strlen(haystack) - len;
289 while(offset <= endpos)
291 found = substring(haystack, offset, len);
300 float NUM_NEAREST_ENTITIES = 4;
301 entity nearest_entity[NUM_NEAREST_ENTITIES];
302 float nearest_length[NUM_NEAREST_ENTITIES];
303 entity findnearest(vector point, .string field, string value, vector axismod)
314 localhead = find(world, field, value);
317 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
318 dist = localhead.oldorigin;
320 dist = localhead.origin;
322 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
325 for (i = 0; i < num_nearest; ++i)
327 if (len < nearest_length[i])
331 // now i tells us where to insert at
332 // INSERTION SORT! YOU'VE SEEN IT! RUN!
333 if (i < NUM_NEAREST_ENTITIES)
335 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
337 nearest_length[j + 1] = nearest_length[j];
338 nearest_entity[j + 1] = nearest_entity[j];
340 nearest_length[i] = len;
341 nearest_entity[i] = localhead;
342 if (num_nearest < NUM_NEAREST_ENTITIES)
343 num_nearest = num_nearest + 1;
346 localhead = find(localhead, field, value);
349 // now use the first one from our list that we can see
350 for (i = 0; i < num_nearest; ++i)
352 traceline(point, nearest_entity[i].origin, TRUE, world);
353 if (trace_fraction == 1)
357 dprint("Nearest point (");
358 dprint(nearest_entity[0].netname);
359 dprint(") is not visible, using a visible one.\n");
361 return nearest_entity[i];
365 if (num_nearest == 0)
368 dprint("Not seeing any location point, using nearest as fallback.\n");
370 dprint("Candidates were: ");
371 for(j = 0; j < num_nearest; ++j)
375 dprint(nearest_entity[j].netname);
380 return nearest_entity[0];
383 void spawnfunc_target_location()
385 self.classname = "target_location";
386 // location name in netname
387 // eventually support: count, teamgame selectors, line of sight?
390 void spawnfunc_info_location()
392 self.classname = "target_location";
393 self.message = self.netname;
396 string NearestLocation(vector p)
401 loc = findnearest(p, classname, "target_location", '1 1 1');
408 loc = findnearest(p, target, "###item###", '1 1 4');
415 string formatmessage(string msg)
426 break; // too many replacements
428 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
429 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
439 replacement = substring(msg, p, 2);
440 escape = substring(msg, p + 1, 1);
443 else if (escape == "\\")
445 else if (escape == "n")
447 else if (escape == "a")
448 replacement = ftos(floor(self.armorvalue));
449 else if (escape == "h")
450 replacement = ftos(floor(self.health));
451 else if (escape == "l")
452 replacement = NearestLocation(self.origin);
453 else if (escape == "y")
454 replacement = NearestLocation(self.cursor_trace_endpos);
455 else if (escape == "d")
456 replacement = NearestLocation(self.death_origin);
457 else if (escape == "w")
462 wep = self.switchweapon;
465 replacement = W_Name(wep);
467 else if (escape == "W")
469 if (self.items & IT_SHELLS) replacement = "shells";
470 else if (self.items & IT_NAILS) replacement = "bullets";
471 else if (self.items & IT_ROCKETS) replacement = "rockets";
472 else if (self.items & IT_CELLS) replacement = "cells";
473 else replacement = "batteries"; // ;)
475 else if (escape == "x")
477 replacement = self.cursor_trace_ent.netname;
478 if (!replacement || !self.cursor_trace_ent)
479 replacement = "nothing";
481 else if (escape == "p")
483 if (self.last_selected_player)
484 replacement = self.last_selected_player.netname;
486 replacement = "(nobody)";
488 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
489 p = p + strlen(replacement);
500 >0: receives a cvar from name=argv(f) value=argv(f+1)
502 void GetCvars_handleString(string thisname, float f, .string field, string name)
507 strunzone(self.field);
508 self.field = string_null;
512 if (thisname == name)
515 strunzone(self.field);
516 self.field = strzone(argv(f + 1));
520 stuffcmd(self, strcat("sendcvar ", name, "\n"));
522 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
524 GetCvars_handleString(thisname, f, field, name);
525 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
526 if (thisname == name)
529 s = func(strcat1(self.field));
532 strunzone(self.field);
533 self.field = strzone(s);
537 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
544 if (thisname == name)
545 self.field = stof(argv(f + 1));
548 stuffcmd(self, strcat("sendcvar ", name, "\n"));
550 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
557 if (thisname == name)
561 self.field = stof(argv(f + 1));
570 stuffcmd(self, strcat("sendcvar ", name, "\n"));
573 string W_FixWeaponOrder_ForceComplete(string s);
574 string W_FixWeaponOrder_AllowIncomplete(string s);
575 float w_getbestweapon(entity e);
576 void GetCvars(float f)
580 s = strcat1(argv(f));
581 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
582 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
583 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
584 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
585 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
586 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
587 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
588 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
589 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
590 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
591 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
592 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
593 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
594 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
595 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
596 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
597 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
598 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
599 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
600 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
601 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
602 #ifdef ALLOW_FORCEMODELS
603 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
604 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
606 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
607 GetCvars_handleFloatOnce(s, f, cvar_cl_noantilag, "cl_noantilag");
610 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
613 if (s == "cl_weaponpriority")
614 self.switchweapon = w_getbestweapon(self);
618 float fexists(string f)
621 fh = fopen(f, FILE_READ);
628 void backtrace(string msg)
631 dev = cvar("developer");
632 war = cvar("prvm_backtraceforwarnings");
633 cvar_set("developer", "1");
634 cvar_set("prvm_backtraceforwarnings", "1");
636 dprint("--- CUT HERE ---\nWARNING: ");
639 remove(world); // isn't there any better way to cause a backtrace?
640 dprint("\n--- CUT UNTIL HERE ---\n");
641 cvar_set("developer", ftos(dev));
642 cvar_set("prvm_backtraceforwarnings", ftos(war));
645 string Team_ColorCode(float teamid)
647 if (teamid == COLOR_TEAM1)
649 else if (teamid == COLOR_TEAM2)
651 else if (teamid == COLOR_TEAM3)
653 else if (teamid == COLOR_TEAM4)
658 string Team_ColorName(float t)
660 // fixme: Search for team entities and get their .netname's!
661 if (t == COLOR_TEAM1)
663 if (t == COLOR_TEAM2)
665 if (t == COLOR_TEAM3)
667 if (t == COLOR_TEAM4)
671 string Team_ColorNameLowerCase(float t)
673 // fixme: Search for team entities and get their .netname's!
674 if (t == COLOR_TEAM1)
676 if (t == COLOR_TEAM2)
678 if (t == COLOR_TEAM3)
680 if (t == COLOR_TEAM4)
685 #define CENTERPRIO_POINT 1
686 #define CENTERPRIO_SPAM 2
687 #define CENTERPRIO_VOTE 4
688 #define CENTERPRIO_NORMAL 5
689 #define CENTERPRIO_SHIELDING 7
690 #define CENTERPRIO_MAPVOTE 9
691 #define CENTERPRIO_IDLEKICK 50
692 #define CENTERPRIO_ADMIN 99
693 .float centerprint_priority;
694 .float centerprint_expires;
695 void centerprint_atprio(entity e, float prio, string s)
697 if (intermission_running)
698 if (prio < CENTERPRIO_MAPVOTE)
700 if (time > e.centerprint_expires)
701 e.centerprint_priority = 0;
702 if (prio >= e.centerprint_priority)
704 e.centerprint_priority = prio;
705 if (timeoutStatus == 2)
706 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
708 e.centerprint_expires = time + e.cvar_scr_centertime;
709 centerprint_builtin(e, s);
712 void centerprint_expire(entity e, float prio)
714 if (prio == e.centerprint_priority)
716 e.centerprint_priority = 0;
717 centerprint_builtin(e, "");
720 void centerprint(entity e, string s)
722 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
725 // decolorizes and team colors the player name when needed
726 string playername(entity p)
729 if (teams_matter && !intermission_running && p.classname == "player")
731 t = Team_ColorCode(p.team);
732 return strcat(t, strdecolorize(p.netname));
738 vector randompos(vector m1, vector m2)
742 v_x = m2_x * random() + m1_x;
743 v_y = m2_y * random() + m1_y;
744 v_z = m2_z * random() + m1_z;
748 float g_pickup_shells;
749 float g_pickup_shells_max;
750 float g_pickup_nails;
751 float g_pickup_nails_max;
752 float g_pickup_rockets;
753 float g_pickup_rockets_max;
754 float g_pickup_cells;
755 float g_pickup_cells_max;
757 float g_pickup_fuel_jetpack;
758 float g_pickup_fuel_max;
759 float g_pickup_armorsmall;
760 float g_pickup_armorsmall_max;
761 float g_pickup_armormedium;
762 float g_pickup_armormedium_max;
763 float g_pickup_armorbig;
764 float g_pickup_armorbig_max;
765 float g_pickup_armorlarge;
766 float g_pickup_armorlarge_max;
767 float g_pickup_healthsmall;
768 float g_pickup_healthsmall_max;
769 float g_pickup_healthmedium;
770 float g_pickup_healthmedium_max;
771 float g_pickup_healthlarge;
772 float g_pickup_healthlarge_max;
773 float g_pickup_healthmega;
774 float g_pickup_healthmega_max;
776 float g_weaponarena_random;
777 string g_weaponarena_list;
778 float g_weaponspeedfactor;
779 float g_weaponratefactor;
780 float g_weapondamagefactor;
781 float g_weaponforcefactor;
785 float start_ammo_shells;
786 float start_ammo_nails;
787 float start_ammo_rockets;
788 float start_ammo_cells;
789 float start_ammo_fuel;
791 float start_armorvalue;
792 float warmup_start_weapons;
793 float warmup_start_ammo_shells;
794 float warmup_start_ammo_nails;
795 float warmup_start_ammo_rockets;
796 float warmup_start_ammo_cells;
797 float warmup_start_ammo_fuel;
798 float warmup_start_health;
799 float warmup_start_armorvalue;
803 entity get_weaponinfo(float w);
805 float NixNex_CanChooseWeapon(float wpn);
806 void readplayerstartcvars()
812 // initialize starting values for players
815 start_ammo_shells = 0;
816 start_ammo_nails = 0;
817 start_ammo_rockets = 0;
818 start_ammo_cells = 0;
819 start_health = cvar("g_balance_health_start");
820 start_armorvalue = cvar("g_balance_armor_start");
823 s = cvar_string("g_weaponarena");
829 g_weaponarena_list = "All Weapons";
830 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
832 e = get_weaponinfo(j);
833 g_weaponarena |= e.weapons;
834 weapon_action(e.weapon, WR_PRECACHE);
837 else if (s == "most")
839 g_weaponarena_list = "Most Weapons";
840 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
842 e = get_weaponinfo(j);
843 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
845 g_weaponarena |= e.weapons;
846 weapon_action(e.weapon, WR_PRECACHE);
850 else if (s == "none")
852 g_weaponarena_list = "No Weapons";
853 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
857 t = tokenize_console(s);
858 g_weaponarena_list = "";
859 for (i = 0; i < t; ++i)
862 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
864 e = get_weaponinfo(j);
867 g_weaponarena |= e.weapons;
868 weapon_action(e.weapon, WR_PRECACHE);
869 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
875 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
878 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
882 g_weaponarena_random = cvar("g_weaponarena_random");
884 g_weaponarena_random = 0;
889 // will be done later
890 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
891 if (NixNex_CanChooseWeapon(i))
892 weapon_action(i, WR_PRECACHE);
893 if(!cvar("g_use_ammunition"))
894 start_items |= IT_UNLIMITED_AMMO;
896 else if (g_weaponarena)
898 start_weapons = g_weaponarena;
899 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
900 start_ammo_rockets = 999;
901 if (g_weaponarena & WEPBIT_SHOTGUN)
902 start_ammo_shells = 999;
903 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
904 start_ammo_cells = 999;
905 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
906 start_ammo_nails = 999;
907 if (g_weaponarena & WEPBIT_HOOK)
908 start_ammo_fuel = 999;
909 start_items |= IT_UNLIMITED_AMMO;
911 else if (g_minstagib)
914 start_armorvalue = 0;
915 start_weapons = WEPBIT_MINSTANEX;
916 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
917 start_ammo_cells = cvar("g_minstagib_ammo_start");
918 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
919 start_ammo_fuel = cvar("g_start_ammo_fuel");
921 if (g_minstagib_invis_alpha <= 0)
922 g_minstagib_invis_alpha = -1;
928 start_ammo_shells = cvar("g_lms_start_ammo_shells");
929 start_ammo_nails = cvar("g_lms_start_ammo_nails");
930 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
931 start_ammo_cells = cvar("g_lms_start_ammo_cells");
932 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
933 start_health = cvar("g_lms_start_health");
934 start_armorvalue = cvar("g_lms_start_armor");
936 else if (cvar("g_use_ammunition"))
938 start_ammo_shells = cvar("g_start_ammo_shells");
939 start_ammo_nails = cvar("g_start_ammo_nails");
940 start_ammo_rockets = cvar("g_start_ammo_rockets");
941 start_ammo_cells = cvar("g_start_ammo_cells");
942 start_ammo_fuel = cvar("g_start_ammo_fuel");
946 start_ammo_shells = cvar("g_pickup_shells_max");
947 start_ammo_nails = cvar("g_pickup_nails_max");
948 start_ammo_rockets = cvar("g_pickup_rockets_max");
949 start_ammo_cells = cvar("g_pickup_cells_max");
950 start_ammo_fuel = cvar("g_pickup_fuel_max");
951 start_items |= IT_UNLIMITED_AMMO;
954 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
956 e = get_weaponinfo(i);
960 t = cvar(strcat("g_start_weapon_", e.netname));
962 if (t < 0) // "default" weapon selection
965 t = (e.spawnflags & WEPSPAWNFLAG_NORMAL);
966 else if (g_race || g_cts)
967 t = (i == WEP_LASER);
969 t = 0; // weapon is set a few lines later
971 t = (i == WEP_LASER || i == WEP_SHOTGUN);
972 if (g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
973 t += (i == WEP_HOOK);
976 if (g_nexball && i == WEP_PORTO)
981 start_weapons |= e.weapons;
982 weapon_action(e.weapon, WR_PRECACHE);
989 warmup_start_ammo_shells = start_ammo_shells;
990 warmup_start_ammo_nails = start_ammo_nails;
991 warmup_start_ammo_rockets = start_ammo_rockets;
992 warmup_start_ammo_cells = start_ammo_cells;
993 warmup_start_ammo_fuel = start_ammo_fuel;
994 warmup_start_health = start_health;
995 warmup_start_armorvalue = start_armorvalue;
996 warmup_start_weapons = start_weapons;
998 if (!g_weaponarena && !g_nixnex && !g_minstagib)
1000 if (cvar("g_use_ammunition"))
1002 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1003 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1004 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1005 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1006 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1008 warmup_start_health = cvar("g_warmup_start_health");
1009 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1010 if (cvar("g_warmup_allguns"))
1012 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1014 e = get_weaponinfo(i);
1017 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
1019 warmup_start_weapons |= e.weapons;
1020 weapon_action(e.weapon, WR_PRECACHE);
1027 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1029 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1030 start_items |= IT_FUEL_REGEN;
1031 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1032 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1036 start_items |= IT_JETPACK;
1038 if (g_weapon_stay == 2)
1040 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1041 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1042 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1043 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1044 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1045 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1046 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1047 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1048 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1049 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1052 start_ammo_shells = max(0, start_ammo_shells);
1053 start_ammo_nails = max(0, start_ammo_nails);
1054 start_ammo_cells = max(0, start_ammo_cells);
1055 start_ammo_rockets = max(0, start_ammo_rockets);
1056 start_ammo_fuel = max(0, start_ammo_fuel);
1058 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1059 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1060 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1061 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1062 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1066 float g_bugrigs_planar_movement;
1067 float g_bugrigs_planar_movement_car_jumping;
1068 float g_bugrigs_reverse_spinning;
1069 float g_bugrigs_reverse_speeding;
1070 float g_bugrigs_reverse_stopping;
1071 float g_bugrigs_air_steering;
1072 float g_bugrigs_angle_smoothing;
1073 float g_bugrigs_friction_floor;
1074 float g_bugrigs_friction_brake;
1075 float g_bugrigs_friction_air;
1076 float g_bugrigs_accel;
1077 float g_bugrigs_speed_ref;
1078 float g_bugrigs_speed_pow;
1079 float g_bugrigs_steer;
1081 float g_touchexplode;
1082 float g_touchexplode_radius;
1083 float g_touchexplode_damage;
1084 float g_touchexplode_edgedamage;
1085 float g_touchexplode_force;
1090 void readlevelcvars(void)
1092 g_bugrigs = cvar("g_bugrigs");
1093 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1094 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1095 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1096 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1097 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1098 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1099 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1100 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1101 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1102 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1103 g_bugrigs_accel = cvar("g_bugrigs_accel");
1104 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1105 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1106 g_bugrigs_steer = cvar("g_bugrigs_steer");
1108 g_touchexplode = cvar("g_touchexplode");
1109 g_touchexplode_radius = cvar("g_touchexplode_radius");
1110 g_touchexplode_damage = cvar("g_touchexplode_damage");
1111 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1112 g_touchexplode_force = cvar("g_touchexplode_force");
1114 #ifdef ALLOW_FORCEMODELS
1115 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1117 sv_loddistance1 = cvar("sv_loddistance1");
1118 sv_loddistance2 = cvar("sv_loddistance2");
1119 if(sv_loddistance2 <= sv_loddistance1)
1120 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1121 sv_clones = cvar("sv_clones");
1122 sv_cheats = cvar("sv_cheats");
1123 sv_gentle = cvar("sv_gentle");
1124 sv_foginterval = cvar("sv_foginterval");
1125 g_cloaked = cvar("g_cloaked");
1126 g_jump_grunt = cvar("g_jump_grunt");
1127 g_footsteps = cvar("g_footsteps");
1128 g_grappling_hook = cvar("g_grappling_hook");
1129 g_jetpack = cvar("g_jetpack");
1130 g_laserguided_missile = cvar("g_laserguided_missile");
1131 g_midair = cvar("g_midair");
1132 g_minstagib = cvar("g_minstagib");
1133 g_nixnex = cvar("g_nixnex");
1134 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1135 g_norecoil = cvar("g_norecoil");
1136 g_vampire = cvar("g_vampire");
1137 g_bloodloss = cvar("g_bloodloss");
1138 sv_maxidle = cvar("sv_maxidle");
1139 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1140 sv_pogostick = cvar("sv_pogostick");
1141 sv_doublejump = cvar("sv_doublejump");
1142 g_ctf_reverse = cvar("g_ctf_reverse");
1143 sv_autotaunt = cvar("sv_autotaunt");
1144 sv_taunt = cvar("sv_taunt");
1146 inWarmupStage = cvar("g_warmup");
1147 g_warmup_limit = cvar("g_warmup_limit");
1148 g_warmup_allguns = cvar("g_warmup_allguns");
1149 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1151 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1152 inWarmupStage = 0; // these modes cannot work together, sorry
1154 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1155 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1156 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1157 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1158 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1159 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1160 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1161 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1162 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1163 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1164 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1165 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1167 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1168 if (g_nixnex) g_weaponarena = 0;
1171 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1172 g_weaponratefactor = cvar("g_weaponratefactor");
1173 g_weapondamagefactor = cvar("g_weapondamagefactor");
1174 g_weaponforcefactor = cvar("g_weaponforcefactor");
1176 g_pickup_shells = cvar("g_pickup_shells");
1177 g_pickup_shells_max = cvar("g_pickup_shells_max");
1178 g_pickup_nails = cvar("g_pickup_nails");
1179 g_pickup_nails_max = cvar("g_pickup_nails_max");
1180 g_pickup_rockets = cvar("g_pickup_rockets");
1181 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1182 g_pickup_cells = cvar("g_pickup_cells");
1183 g_pickup_cells_max = cvar("g_pickup_cells_max");
1184 g_pickup_fuel = cvar("g_pickup_fuel");
1185 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1186 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1187 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1188 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1189 g_pickup_armormedium = cvar("g_pickup_armormedium");
1190 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1191 g_pickup_armorbig = cvar("g_pickup_armorbig");
1192 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1193 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1194 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1195 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1196 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1197 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1198 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1199 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1200 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1201 g_pickup_healthmega = cvar("g_pickup_healthmega");
1202 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1204 g_pinata = cvar("g_pinata");
1206 g_weapon_stay = cvar("g_weapon_stay");
1207 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1209 g_ghost_items = cvar("g_ghost_items");
1210 if(g_ghost_items >= 1)
1211 g_ghost_items = 0.13; // default alpha value
1213 if not(inWarmupStage)
1214 game_starttime = cvar("g_start_delay");
1216 readplayerstartcvars();
1220 // TODO sound pack system
1223 string precache_sound_builtin (string s) = #19;
1224 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1225 string precache_sound(string s)
1227 return precache_sound_builtin(strcat(soundpack, s));
1229 void play2(entity e, string filename)
1231 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1233 void sound(entity e, float chan, string samp, float vol, float atten)
1235 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1240 string precache_sound (string s) = #19;
1241 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1242 float precache_sound_index (string s) = #19;
1244 #define SND_VOLUME 1
1245 #define SND_ATTENUATION 2
1246 #define SND_LARGEENTITY 8
1247 #define SND_LARGESOUND 16
1249 float sound_allowed(float dest, entity e)
1251 // sounds from world may always pass
1254 if (e.classname == "body")
1256 if (e.owner && e.owner != e)
1261 // sounds to self may always pass
1262 if (dest == MSG_ONE)
1263 if (e == msg_entity)
1265 // sounds by players can be removed
1266 if (cvar("bot_sound_monopoly"))
1267 if (clienttype(e) == CLIENTTYPE_REAL)
1269 // anything else may pass
1273 void sound(entity e, float chan, string samp, float vol, float atten)
1275 if (!sound_allowed(MSG_BROADCAST, e))
1277 sound_builtin(e, chan, samp, vol, atten);
1279 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1283 if (!sound_allowed(dest, e))
1286 entno = num_for_edict(e);
1287 idx = precache_sound_index(samp);
1292 atten = floor(atten * 64);
1293 vol = floor(vol * 255);
1296 sflags |= SND_VOLUME;
1298 sflags |= SND_ATTENUATION;
1300 sflags |= SND_LARGEENTITY;
1302 sflags |= SND_LARGESOUND;
1304 WriteByte(dest, SVC_SOUND);
1305 WriteByte(dest, sflags);
1306 if (sflags & SND_VOLUME)
1307 WriteByte(dest, vol);
1308 if (sflags & SND_ATTENUATION)
1309 WriteByte(dest, atten);
1310 if (sflags & SND_LARGEENTITY)
1312 WriteShort(dest, entno);
1313 WriteByte(dest, chan);
1317 WriteShort(dest, entno * 8 + chan);
1319 if (sflags & SND_LARGESOUND)
1320 WriteShort(dest, idx);
1322 WriteByte(dest, idx);
1324 WriteCoord(dest, o_x);
1325 WriteCoord(dest, o_y);
1326 WriteCoord(dest, o_z);
1328 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1332 if (!sound_allowed(dest, e))
1335 o = e.origin + 0.5 * (e.mins + e.maxs);
1336 soundtoat(dest, e, o, chan, samp, vol, atten);
1338 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1340 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1342 void stopsoundto(float dest, entity e, float chan)
1346 if (!sound_allowed(dest, e))
1349 entno = num_for_edict(e);
1354 idx = precache_sound_index("misc/null.wav");
1355 sflags = SND_LARGEENTITY;
1357 sflags |= SND_LARGESOUND;
1358 WriteByte(dest, SVC_SOUND);
1359 WriteByte(dest, sflags);
1360 WriteShort(dest, entno);
1361 WriteByte(dest, chan);
1362 if (sflags & SND_LARGESOUND)
1363 WriteShort(dest, idx);
1365 WriteByte(dest, idx);
1366 WriteCoord(dest, e.origin_x);
1367 WriteCoord(dest, e.origin_y);
1368 WriteCoord(dest, e.origin_z);
1372 WriteByte(dest, SVC_STOPSOUND);
1373 WriteShort(dest, entno * 8 + chan);
1376 void stopsound(entity e, float chan)
1378 if (!sound_allowed(MSG_BROADCAST, e))
1381 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1382 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1385 void play2(entity e, string filename)
1387 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1389 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1392 .float announcetime;
1393 float announce(entity player, string msg)
1395 if (time > player.announcetime)
1396 if (clienttype(player) == CLIENTTYPE_REAL)
1398 player.announcetime = time + 0.8;
1404 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1405 float spamsound(entity e, float chan, string samp, float vol, float atten)
1407 if (!sound_allowed(MSG_BROADCAST, e))
1410 if (time > e.announcetime)
1412 e.announcetime = time;
1413 sound(e, chan, samp, vol, atten);
1419 void play2team(float t, string filename)
1423 if (cvar("bot_sound_monopoly"))
1426 FOR_EACH_REALPLAYER(head)
1429 play2(head, filename);
1433 void play2all(string samp)
1435 if (cvar("bot_sound_monopoly"))
1438 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1441 void PrecachePlayerSounds(string f);
1442 void precache_all_models(string pattern)
1444 float globhandle, i, n;
1447 globhandle = search_begin(pattern, TRUE, FALSE);
1450 n = search_getsize(globhandle);
1451 for (i = 0; i < n; ++i)
1453 //print(search_getfilename(globhandle, i), "\n");
1454 f = search_getfilename(globhandle, i);
1457 if(substring(f, -9,5) == "_lod1")
1459 if(substring(f, -9,5) == "_lod2")
1461 if(!sv_loddistance1)
1463 PrecachePlayerSounds(strcat(f, ".sounds"));
1465 search_end(globhandle);
1470 // gamemode related things
1471 precache_model ("models/misc/chatbubble.spr");
1472 precache_model ("models/misc/teambubble.spr");
1475 precache_model ("models/runematch/curse.mdl");
1476 precache_model ("models/runematch/rune.mdl");
1479 #ifdef TTURRETS_ENABLED
1480 if (cvar("g_turrets"))
1484 // Precache all player models if desired
1485 if (cvar("sv_precacheplayermodels"))
1487 PrecachePlayerSounds("sound/player/default.sounds");
1488 precache_all_models("models/player/*.zym");
1489 precache_all_models("models/player/*.dpm");
1490 precache_all_models("models/player/*.md3");
1491 precache_all_models("models/player/*.psk");
1492 //precache_model("models/player/carni.zym");
1493 //precache_model("models/player/crash.zym");
1494 //precache_model("models/player/grunt.zym");
1495 //precache_model("models/player/headhunter.zym");
1496 //precache_model("models/player/insurrectionist.zym");
1497 //precache_model("models/player/jeandarc.zym");
1498 //precache_model("models/player/lurk.zym");
1499 //precache_model("models/player/lycanthrope.zym");
1500 //precache_model("models/player/marine.zym");
1501 //precache_model("models/player/nexus.zym");
1502 //precache_model("models/player/pyria.zym");
1503 //precache_model("models/player/shock.zym");
1504 //precache_model("models/player/skadi.zym");
1505 //precache_model("models/player/specop.zym");
1506 //precache_model("models/player/visitant.zym");
1509 if (cvar("sv_defaultcharacter"))
1512 s = cvar_string("sv_defaultplayermodel_red");
1516 PrecachePlayerSounds(strcat(s, ".sounds"));
1518 s = cvar_string("sv_defaultplayermodel_blue");
1522 PrecachePlayerSounds(strcat(s, ".sounds"));
1524 s = cvar_string("sv_defaultplayermodel_yellow");
1528 PrecachePlayerSounds(strcat(s, ".sounds"));
1530 s = cvar_string("sv_defaultplayermodel_pink");
1534 PrecachePlayerSounds(strcat(s, ".sounds"));
1536 s = cvar_string("sv_defaultplayermodel");
1540 PrecachePlayerSounds(strcat(s, ".sounds"));
1546 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1547 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1550 // gore and miscellaneous sounds
1551 //precache_sound ("misc/h2ohit.wav");
1552 precache_model ("models/hook.md3");
1553 precache_sound ("misc/armorimpact.wav");
1554 precache_sound ("misc/bodyimpact1.wav");
1555 precache_sound ("misc/bodyimpact2.wav");
1556 precache_sound ("misc/gib.wav");
1557 precache_sound ("misc/gib_splat01.wav");
1558 precache_sound ("misc/gib_splat02.wav");
1559 precache_sound ("misc/gib_splat03.wav");
1560 precache_sound ("misc/gib_splat04.wav");
1561 precache_sound ("misc/hit.wav");
1562 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1563 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1564 precache_sound ("misc/null.wav");
1565 precache_sound ("misc/spawn.wav");
1566 precache_sound ("misc/talk.wav");
1567 precache_sound ("misc/teleport.wav");
1568 precache_sound ("misc/poweroff.wav");
1569 precache_sound ("player/lava.wav");
1570 precache_sound ("player/slime.wav");
1573 precache_sound ("misc/jetpack_fly.wav");
1575 // announcer sounds - male
1576 precache_sound ("announcer/male/electrobitch.wav");
1577 precache_sound ("announcer/male/airshot.wav");
1578 precache_sound ("announcer/male/03kills.wav");
1579 precache_sound ("announcer/male/05kills.wav");
1580 precache_sound ("announcer/male/10kills.wav");
1581 precache_sound ("announcer/male/15kills.wav");
1582 precache_sound ("announcer/male/20kills.wav");
1583 precache_sound ("announcer/male/25kills.wav");
1584 precache_sound ("announcer/male/30kills.wav");
1585 precache_sound ("announcer/male/botlike.wav");
1586 precache_sound ("announcer/male/yoda.wav");
1587 precache_sound ("announcer/male/amazing.wav");
1588 precache_sound ("announcer/male/awesome.wav");
1589 precache_sound ("announcer/male/headshot.wav");
1590 precache_sound ("announcer/male/impressive.wav");
1592 // announcer sounds - robotic
1593 precache_sound ("announcer/robotic/prepareforbattle.wav");
1594 precache_sound ("announcer/robotic/begin.wav");
1595 precache_sound ("announcer/robotic/timeoutcalled.wav");
1596 precache_sound ("announcer/robotic/1fragleft.wav");
1597 precache_sound ("announcer/robotic/2fragsleft.wav");
1598 precache_sound ("announcer/robotic/3fragsleft.wav");
1599 precache_sound ("announcer/robotic/terminated.wav");
1602 precache_sound ("announcer/robotic/lastsecond.wav");
1603 precache_sound ("announcer/robotic/narrowly.wav");
1606 precache_model ("models/sprites/0.spr32");
1607 precache_model ("models/sprites/1.spr32");
1608 precache_model ("models/sprites/2.spr32");
1609 precache_model ("models/sprites/3.spr32");
1610 precache_model ("models/sprites/4.spr32");
1611 precache_model ("models/sprites/5.spr32");
1612 precache_model ("models/sprites/6.spr32");
1613 precache_model ("models/sprites/7.spr32");
1614 precache_model ("models/sprites/8.spr32");
1615 precache_model ("models/sprites/9.spr32");
1616 precache_model ("models/sprites/10.spr32");
1617 precache_sound ("announcer/robotic/1.wav");
1618 precache_sound ("announcer/robotic/2.wav");
1619 precache_sound ("announcer/robotic/3.wav");
1620 precache_sound ("announcer/robotic/4.wav");
1621 precache_sound ("announcer/robotic/5.wav");
1622 precache_sound ("announcer/robotic/6.wav");
1623 precache_sound ("announcer/robotic/7.wav");
1624 precache_sound ("announcer/robotic/8.wav");
1625 precache_sound ("announcer/robotic/9.wav");
1626 precache_sound ("announcer/robotic/10.wav");
1628 // common weapon precaches
1629 precache_sound ("weapons/weapon_switch.wav");
1630 precache_sound ("weapons/weaponpickup.wav");
1631 precache_sound ("weapons/unavailable.wav");
1632 if (g_grappling_hook)
1634 precache_sound ("weapons/hook_fire.wav"); // hook
1635 precache_sound ("weapons/hook_impact.wav"); // hook
1638 if (cvar("sv_precacheweapons") || g_nixnex)
1640 //precache weapon models/sounds
1643 while (wep <= WEP_LAST)
1645 weapon_action(wep, WR_PRECACHE);
1650 precache_model("models/elaser.mdl");
1651 precache_model("models/laser.mdl");
1652 precache_model("models/ebomb.mdl");
1655 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1657 if (!self.noise && self.music) // quake 3 uses the music field
1658 self.noise = self.music;
1660 // plays music for the level if there is any
1663 precache_sound (self.noise);
1664 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1669 // sorry, but using \ in macros breaks line numbers
1670 #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
1671 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1672 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1674 vector ExactTriggerHit_mins;
1675 vector ExactTriggerHit_maxs;
1676 float ExactTriggerHit_Recurse()
1682 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1685 if (trace_ent == self)
1690 se.solid = SOLID_NOT;
1691 f = ExactTriggerHit_Recurse();
1697 float ExactTriggerHit()
1701 if not(self.modelindex)
1705 self.solid = SOLID_BSP;
1706 ExactTriggerHit_mins = other.absmin;
1707 ExactTriggerHit_maxs = other.absmax;
1708 f = ExactTriggerHit_Recurse();
1714 // WARNING: this kills the trace globals
1715 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1716 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1718 #define INITPRIO_FIRST 0
1719 #define INITPRIO_GAMETYPE 0
1720 #define INITPRIO_GAMETYPE_FALLBACK 1
1721 #define INITPRIO_CVARS 5
1722 #define INITPRIO_FINDTARGET 10
1723 #define INITPRIO_DROPTOFLOOR 20
1724 #define INITPRIO_SETLOCATION 90
1725 #define INITPRIO_LINKDOORS 91
1726 #define INITPRIO_LAST 99
1728 .void(void) initialize_entity;
1729 .float initialize_entity_order;
1730 .entity initialize_entity_next;
1731 entity initialize_entity_first;
1733 void make_safe_for_remove(entity e)
1735 if (e.initialize_entity)
1738 for (ent = initialize_entity_first; ent; )
1740 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1742 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1743 // skip it in linked list
1746 prev.initialize_entity_next = ent.initialize_entity_next;
1747 ent = prev.initialize_entity_next;
1751 initialize_entity_first = ent.initialize_entity_next;
1752 ent = initialize_entity_first;
1758 ent = ent.initialize_entity_next;
1764 void objerror(string s)
1766 make_safe_for_remove(self);
1767 objerror_builtin(s);
1770 void remove_unsafely(entity e)
1775 void remove_safely(entity e)
1777 make_safe_for_remove(e);
1781 void InitializeEntity(entity e, void(void) func, float order)
1785 if (!e || e.initialize_entity)
1787 // make a proxy initializer entity
1791 e.classname = "initialize_entity";
1795 e.initialize_entity = func;
1796 e.initialize_entity_order = order;
1798 cur = initialize_entity_first;
1801 if (!cur || cur.initialize_entity_order > order)
1803 // insert between prev and cur
1805 prev.initialize_entity_next = e;
1807 initialize_entity_first = e;
1808 e.initialize_entity_next = cur;
1812 cur = cur.initialize_entity_next;
1815 void InitializeEntitiesRun()
1818 startoflist = initialize_entity_first;
1819 initialize_entity_first = world;
1820 for (self = startoflist; self; )
1823 var void(void) func;
1824 e = self.initialize_entity_next;
1825 func = self.initialize_entity;
1826 self.initialize_entity_order = 0;
1827 self.initialize_entity = func_null;
1828 self.initialize_entity_next = world;
1829 if (self.classname == "initialize_entity")
1833 remove_builtin(self);
1836 //dprint("Delayed initialization: ", self.classname, "\n");
1842 .float uncustomizeentityforclient_set;
1843 .void(void) uncustomizeentityforclient;
1844 void(void) SUB_Nullpointer = #0;
1845 void UncustomizeEntitiesRun()
1849 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1850 self.uncustomizeentityforclient();
1853 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1855 e.customizeentityforclient = customizer;
1856 e.uncustomizeentityforclient = uncustomizer;
1857 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1861 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1864 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1868 if (e.classname == "")
1869 e.classname = "net_linked";
1871 if (e.model == "" || self.modelindex == 0)
1875 setmodel(e, "null");
1879 e.SendEntity = sendfunc;
1880 e.SendFlags = 0xFFFFFF;
1883 e.effects |= EF_NODEPTHTEST;
1887 e.nextthink = time + dt;
1888 e.think = SUB_Remove;
1892 void adaptor_think2touch()
1901 void adaptor_think2use()
1913 // deferred dropping
1914 void DropToFloor_Handler()
1916 droptofloor_builtin();
1917 self.dropped_origin = self.origin;
1922 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1927 float trace_hits_box_a0, trace_hits_box_a1;
1929 float trace_hits_box_1d(float end, float thmi, float thma)
1933 // just check if x is in range
1941 // do the trace with respect to x
1942 // 0 -> end has to stay in thmi -> thma
1943 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1944 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1945 if (trace_hits_box_a0 > trace_hits_box_a1)
1951 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1956 // now it is a trace from 0 to end
1958 trace_hits_box_a0 = 0;
1959 trace_hits_box_a1 = 1;
1961 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1963 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1965 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1971 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1973 return trace_hits_box(start, end, thmi - ma, thma - mi);
1976 float SUB_NoImpactCheck()
1978 // zero hitcontents = this is not the real impact, but either the
1979 // mirror-impact of something hitting the projectile instead of the
1980 // projectile hitting the something, or a touchareagrid one. Neither of
1981 // these stop the projectile from moving, so...
1982 if(trace_dphitcontents == 0)
1984 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1987 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1989 if (other == world && self.size != '0 0 0')
1992 tic = self.velocity * sys_ticrate;
1993 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1994 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1995 if (trace_fraction >= 1)
1997 dprint("Odd... did not hit...?\n");
1999 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2001 dprint("Detected and prevented the sky-grapple bug.\n");
2009 #define SUB_OwnerCheck() (other && (other == self.owner))
2011 #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)
2013 float MAX_IPBAN_URIS = 16;
2015 float URI_GET_DISCARD = 0;
2016 float URI_GET_IPBAN = 1;
2017 float URI_GET_IPBAN_END = 16;
2019 void URI_Get_Callback(float id, float status, string data)
2021 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2023 dprint("\nEnd of data.\n");
2025 if (id == URI_GET_DISCARD)
2029 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2032 OnlineBanList_URI_Get_Callback(id, status, data);
2036 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2040 void print_to(entity e, string s)
2043 sprint(e, strcat(s, "\n"));
2062 for (i = 0; i < MapInfo_count; ++i)
2064 if (MapInfo_Get_ByID(i))
2066 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2069 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2070 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2078 for (i = 0; i < MapInfo_count; ++i)
2080 if (MapInfo_Get_ByID(i))
2082 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2085 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2086 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2094 for (i = 0; i < MapInfo_count; ++i)
2096 if (MapInfo_Get_ByID(i))
2098 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2101 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2102 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2108 MapInfo_ClearTemps();
2111 return "No records are available on this server.\n";
2113 return strcat("Records on this server:\n", s);
2116 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2119 vector start, org, delta, end, enddown, mstart;
2121 m = e.dphitcontentsmask;
2122 e.dphitcontentsmask = goodcontents | badcontents;
2125 delta = world.maxs - world.mins;
2127 for (i = 0; i < attempts; ++i)
2129 start_x = org_x + random() * delta_x;
2130 start_y = org_y + random() * delta_y;
2131 start_z = org_z + random() * delta_z;
2133 // rule 1: start inside world bounds, and outside
2134 // solid, and don't start from somewhere where you can
2135 // fall down to evil
2136 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2137 if (trace_fraction >= 1)
2139 if (trace_startsolid)
2141 if (trace_dphitcontents & badcontents)
2143 if (trace_dphitq3surfaceflags & badsurfaceflags)
2146 // rule 2: if we are too high, lower the point
2147 if (trace_fraction * delta_z > maxaboveground)
2148 start = trace_endpos + '0 0 1' * maxaboveground;
2149 enddown = trace_endpos;
2151 // rule 3: make sure we aren't outside the map. This only works
2152 // for somewhat well formed maps. A good rule of thumb is that
2153 // the map should have a convex outside hull.
2154 // these can be traceLINES as we already verified the starting box
2155 mstart = start + 0.5 * (e.mins + e.maxs);
2156 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2157 if (trace_fraction >= 1)
2159 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2160 if (trace_fraction >= 1)
2162 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2163 if (trace_fraction >= 1)
2165 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2166 if (trace_fraction >= 1)
2168 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2169 if (trace_fraction >= 1)
2172 // find a random vector to "look at"
2173 end_x = org_x + random() * delta_x;
2174 end_y = org_y + random() * delta_y;
2175 end_z = org_z + random() * delta_z;
2176 end = start + normalize(end - start) * vlen(delta);
2178 // rule 4: start TO end must not be too short
2179 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2180 if (trace_startsolid)
2182 if (trace_fraction < minviewdistance / vlen(delta))
2185 // rule 5: don't want to look at sky
2186 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2189 // rule 6: we must not end up in trigger_hurt
2190 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2192 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2199 e.dphitcontentsmask = m;
2203 setorigin(e, start);
2204 e.angles = vectoangles(end - start);
2205 dprint("Needed ", ftos(i + 1), " attempts\n");
2212 float zcurveparticles_effectno;
2213 vector zcurveparticles_start;
2214 float zcurveparticles_spd;
2216 void endzcurveparticles()
2218 if(zcurveparticles_effectno)
2221 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2223 zcurveparticles_effectno = 0;
2226 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2228 spd = bound(0, floor(spd / 16), 32767);
2229 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2231 endzcurveparticles();
2232 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2233 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2234 WriteShort(MSG_BROADCAST, effectno);
2235 WriteCoord(MSG_BROADCAST, start_x);
2236 WriteCoord(MSG_BROADCAST, start_y);
2237 WriteCoord(MSG_BROADCAST, start_z);
2238 zcurveparticles_effectno = effectno;
2239 zcurveparticles_start = start;
2242 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2243 WriteCoord(MSG_BROADCAST, end_x);
2244 WriteCoord(MSG_BROADCAST, end_y);
2245 WriteCoord(MSG_BROADCAST, end_z);
2246 WriteCoord(MSG_BROADCAST, end_dz);
2247 zcurveparticles_spd = spd;
2250 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2253 vector vecxy, velxy;
2255 vecxy = end - start;
2260 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2262 endzcurveparticles();
2263 trailparticles(world, effectno, start, end);
2267 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2268 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2271 string GetGametype(); // g_world.qc
2272 void write_recordmarker(entity pl, float tstart, float dt)
2274 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2276 // also write a marker into demo files for demotc-race-record-extractor to find
2279 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2280 " ", ftos(tstart), " ", ftos(dt), "\n"));
2283 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2285 switch(self.owner.cvar_cl_gunalign)
2296 if(allowcenter) // 2: allow center handedness
2309 if(allowcenter) // 2: allow center handedness
2325 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2330 if (cvar("g_shootfromeye"))
2334 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2342 else if (cvar("g_shootfromcenter"))
2346 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2354 else if (cvar("g_shootfromclient"))
2356 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2358 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2373 void attach_sameorigin(entity e, entity to, string tag)
2375 vector org, t_forward, t_left, t_up, e_forward, e_up;
2382 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2383 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2384 t_forward = v_forward * tagscale;
2385 t_left = v_right * -tagscale;
2386 t_up = v_up * tagscale;
2388 e.origin_x = org * t_forward;
2389 e.origin_y = org * t_left;
2390 e.origin_z = org * t_up;
2392 // current forward and up directions
2393 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2394 e.angles_x = -e.angles_x;
2395 fixedmakevectors(e.angles);
2397 // untransform forward, up!
2398 e_forward_x = v_forward * t_forward;
2399 e_forward_y = v_forward * t_left;
2400 e_forward_z = v_forward * t_up;
2401 e_up_x = v_up * t_forward;
2402 e_up_y = v_up * t_left;
2403 e_up_z = v_up * t_up;
2405 e.angles = fixedvectoangles2(e_forward, e_up);
2406 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2407 e.angles_x = -e.angles_x;
2409 setattachment(e, to, tag);
2410 setorigin(e, e.origin);
2413 void detach_sameorigin(entity e)
2416 org = gettaginfo(e, 0);
2417 e.angles = fixedvectoangles2(v_forward, v_up);
2418 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2419 e.angles_x = -e.angles_x;
2421 setattachment(e, world, "");
2422 setorigin(e, e.origin);
2425 void follow_sameorigin(entity e, entity to)
2427 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2428 e.aiment = to; // make the hole follow bmodel
2429 e.punchangle = to.angles; // the original angles of bmodel
2430 e.view_ofs = e.origin - to.origin; // relative origin
2431 e.v_angle = e.angles - to.angles; // relative angles
2434 void unfollow_sameorigin(entity e)
2436 e.movetype = MOVETYPE_NONE;
2439 entity gettaginfo_relative_ent;
2440 vector gettaginfo_relative(entity e, float tag)
2442 if (!gettaginfo_relative_ent)
2444 gettaginfo_relative_ent = spawn();
2445 gettaginfo_relative_ent.effects = EF_NODRAW;
2447 gettaginfo_relative_ent.model = e.model;
2448 gettaginfo_relative_ent.modelindex = e.modelindex;
2449 gettaginfo_relative_ent.frame = e.frame;
2450 return gettaginfo(gettaginfo_relative_ent, tag);
2453 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2457 if (pl.soundentity.cnt & p)
2459 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2460 pl.soundentity.cnt |= p;
2463 void SoundEntity_StopSound(entity pl, float chan)
2467 if (pl.soundentity.cnt & p)
2469 stopsoundto(MSG_ALL, pl.soundentity, chan);
2470 pl.soundentity.cnt &~= p;
2474 void SoundEntity_Attach(entity pl)
2476 pl.soundentity = spawn();
2477 pl.soundentity.classname = "soundentity";
2478 pl.soundentity.owner = pl;
2479 setattachment(pl.soundentity, pl, "");
2480 setmodel(pl.soundentity, "null");
2483 void SoundEntity_Detach(entity pl)
2486 for (i = 0; i <= 7; ++i)
2487 SoundEntity_StopSound(pl, i);
2491 float ParseCommandPlayerSlotTarget_firsttoken;
2492 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2500 ParseCommandPlayerSlotTarget_firsttoken = -1;
2504 if (substring(argv(idx), 0, 1) == "#")
2506 s = substring(argv(idx), 1, -1);
2514 ParseCommandPlayerSlotTarget_firsttoken = idx;
2515 if (s == ftos(stof(s)))
2517 e = edict_num(stof(s));
2518 if (e.flags & FL_CLIENT)
2524 // it must be a nick name
2527 ParseCommandPlayerSlotTarget_firsttoken = idx;
2530 FOR_EACH_CLIENT(head)
2531 if (head.netname == s)
2539 s = strdecolorize(s);
2541 FOR_EACH_CLIENT(head)
2542 if (strdecolorize(head.netname) == s)
2557 float modeleffect_SendEntity(entity to, float sf)
2560 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2563 if(self.velocity != '0 0 0')
2565 if(self.angles != '0 0 0')
2567 if(self.avelocity != '0 0 0')
2570 WriteByte(MSG_ENTITY, f);
2571 WriteShort(MSG_ENTITY, self.modelindex);
2572 WriteByte(MSG_ENTITY, self.skin);
2573 WriteByte(MSG_ENTITY, self.frame);
2574 WriteCoord(MSG_ENTITY, self.origin_x);
2575 WriteCoord(MSG_ENTITY, self.origin_y);
2576 WriteCoord(MSG_ENTITY, self.origin_z);
2579 WriteCoord(MSG_ENTITY, self.velocity_x);
2580 WriteCoord(MSG_ENTITY, self.velocity_y);
2581 WriteCoord(MSG_ENTITY, self.velocity_z);
2585 WriteCoord(MSG_ENTITY, self.angles_x);
2586 WriteCoord(MSG_ENTITY, self.angles_y);
2587 WriteCoord(MSG_ENTITY, self.angles_z);
2591 WriteCoord(MSG_ENTITY, self.avelocity_x);
2592 WriteCoord(MSG_ENTITY, self.avelocity_y);
2593 WriteCoord(MSG_ENTITY, self.avelocity_z);
2595 WriteShort(MSG_ENTITY, self.scale * 256.0);
2596 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2597 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2598 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2599 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2604 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)
2609 e.classname = "modeleffect";
2617 e.teleport_time = t1;
2621 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2625 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2628 sz = max(e.scale, e.scale2);
2629 setsize(e, e.mins * sz, e.maxs * sz);
2630 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2633 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2635 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2638 float randombit(float bits)
2640 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2649 for(f = 1; f <= bits; f *= 2)
2658 r = (r - 1) / (n - 1);
2665 float randombits(float bits, float k, float error_return)
2669 while(k > 0 && bits != r)
2671 r += randombit(bits - r);
2680 void randombit_test(float bits, float iter)
2684 print(ftos(randombit(bits)), "\n");
2689 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2691 if(halflifedist > 0)
2692 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2693 else if(halflifedist < 0)
2694 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);