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 e.origin = 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 void bcenterprint(string s)
116 // TODO replace by MSG_ALL (would show it to spectators too, though)?
118 FOR_EACH_PLAYER(head)
119 if (clienttype(head) == CLIENTTYPE_REAL)
120 centerprint(head, s);
123 void GameLogEcho(string s)
128 if (cvar("sv_eventlog_files"))
133 matches = cvar("sv_eventlog_files_counter") + 1;
134 cvar_set("sv_eventlog_files_counter", ftos(matches));
137 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
138 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
139 logfile = fopen(fn, FILE_APPEND);
140 fputs(logfile, ":logversion:3\n");
144 if (cvar("sv_eventlog_files_timestamps"))
145 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
147 fputs(logfile, strcat(s, "\n"));
150 if (cvar("sv_eventlog_console"))
159 // will be opened later
164 if (logfile_open && logfile >= 0)
171 float spawnpoint_nag;
172 void relocate_spawnpoint()
174 // nudge off the floor
175 setorigin(self, self.origin + '0 0 1');
177 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
178 if (trace_startsolid)
184 if (!move_out_of_solid(self))
185 objerror("could not get out of solid at all!");
186 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
187 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
188 print(" ", ftos(self.origin_y - o_y));
189 print(" ", ftos(self.origin_z - o_z), "'\n");
190 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
193 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
199 self.mins = self.maxs = '0 0 0';
200 objerror("player spawn point in solid, mapper sucks!\n");
205 if (cvar("g_spawnpoints_autodrop"))
207 setsize(self, PL_MIN, PL_MAX);
211 self.use = spawnpoint_use;
212 self.team_saved = self.team;
216 if (g_ctf || g_assault || g_onslaught || g_domination || g_nexball)
218 have_team_spawns = 1;
220 if (cvar("r_showbboxes"))
222 // show where spawnpoints point at too
223 makevectors(self.angles);
226 e.classname = "info_player_foo";
227 setorigin(e, self.origin + v_forward * 24);
228 setsize(e, '-8 -8 -8', '8 8 8');
229 e.solid = SOLID_TRIGGER;
233 #define strstr strstrofs
235 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
236 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
237 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
238 // BE CONSTANT OR strzoneD!
239 float strstr(string haystack, string needle, float offset)
243 len = strlen(needle);
244 endpos = strlen(haystack) - len;
245 while(offset <= endpos)
247 found = substring(haystack, offset, len);
256 float NUM_NEAREST_ENTITIES = 4;
257 entity nearest_entity[NUM_NEAREST_ENTITIES];
258 float nearest_length[NUM_NEAREST_ENTITIES];
259 entity findnearest(vector point, .string field, string value, vector axismod)
270 localhead = find(world, field, value);
273 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
274 dist = localhead.oldorigin;
276 dist = localhead.origin;
278 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
281 for (i = 0; i < num_nearest; ++i)
283 if (len < nearest_length[i])
287 // now i tells us where to insert at
288 // INSERTION SORT! YOU'VE SEEN IT! RUN!
289 if (i < NUM_NEAREST_ENTITIES)
291 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
293 nearest_length[j + 1] = nearest_length[j];
294 nearest_entity[j + 1] = nearest_entity[j];
296 nearest_length[i] = len;
297 nearest_entity[i] = localhead;
298 if (num_nearest < NUM_NEAREST_ENTITIES)
299 num_nearest = num_nearest + 1;
302 localhead = find(localhead, field, value);
305 // now use the first one from our list that we can see
306 for (i = 0; i < num_nearest; ++i)
308 traceline(point, nearest_entity[i].origin, TRUE, world);
309 if (trace_fraction == 1)
313 dprint("Nearest point (");
314 dprint(nearest_entity[0].netname);
315 dprint(") is not visible, using a visible one.\n");
317 return nearest_entity[i];
321 if (num_nearest == 0)
324 dprint("Not seeing any location point, using nearest as fallback.\n");
326 dprint("Candidates were: ");
327 for(j = 0; j < num_nearest; ++j)
331 dprint(nearest_entity[j].netname);
336 return nearest_entity[0];
339 void spawnfunc_target_location()
341 self.classname = "target_location";
342 // location name in netname
343 // eventually support: count, teamgame selectors, line of sight?
346 void spawnfunc_info_location()
348 self.classname = "target_location";
349 self.message = self.netname;
352 string NearestLocation(vector p)
357 loc = findnearest(p, classname, "target_location", '1 1 1');
364 loc = findnearest(p, target, "###item###", '1 1 4');
371 string formatmessage(string msg)
382 break; // too many replacements
384 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
385 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
395 replacement = substring(msg, p, 2);
396 escape = substring(msg, p + 1, 1);
399 else if (escape == "\\")
401 else if (escape == "n")
403 else if (escape == "a")
404 replacement = ftos(floor(self.armorvalue));
405 else if (escape == "h")
406 replacement = ftos(floor(self.health));
407 else if (escape == "l")
408 replacement = NearestLocation(self.origin);
409 else if (escape == "y")
410 replacement = NearestLocation(self.cursor_trace_endpos);
411 else if (escape == "d")
412 replacement = NearestLocation(self.death_origin);
413 else if (escape == "w")
418 wep = self.switchweapon;
421 replacement = W_Name(wep);
423 else if (escape == "W")
425 if (self.items & IT_SHELLS) replacement = "shells";
426 else if (self.items & IT_NAILS) replacement = "bullets";
427 else if (self.items & IT_ROCKETS) replacement = "rockets";
428 else if (self.items & IT_CELLS) replacement = "cells";
429 else replacement = "batteries"; // ;)
431 else if (escape == "x")
433 replacement = self.cursor_trace_ent.netname;
434 if (!replacement || !self.cursor_trace_ent)
435 replacement = "nothing";
437 else if (escape == "p")
439 if (self.last_selected_player)
440 replacement = self.last_selected_player.netname;
442 replacement = "(nobody)";
444 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
445 p = p + strlen(replacement);
456 >0: receives a cvar from name=argv(f) value=argv(f+1)
458 void GetCvars_handleString(string thisname, float f, .string field, string name)
463 strunzone(self.field);
464 self.field = string_null;
468 if (thisname == name)
471 strunzone(self.field);
472 self.field = strzone(argv(f + 1));
476 stuffcmd(self, strcat("sendcvar ", name, "\n"));
478 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
480 GetCvars_handleString(thisname, f, field, name);
481 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
482 if (thisname == name)
485 s = func(strcat1(self.field));
488 strunzone(self.field);
489 self.field = strzone(s);
493 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
500 if (thisname == name)
501 self.field = stof(argv(f + 1));
504 stuffcmd(self, strcat("sendcvar ", name, "\n"));
506 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
513 if (thisname == name)
517 self.field = stof(argv(f + 1));
526 stuffcmd(self, strcat("sendcvar ", name, "\n"));
529 string W_FixWeaponOrder_ForceComplete(string s);
530 string W_FixWeaponOrder_AllowIncomplete(string s);
531 float w_getbestweapon(entity e);
532 void GetCvars(float f)
536 s = strcat1(argv(f));
537 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
538 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
539 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
540 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
541 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
542 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
543 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
544 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
545 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
546 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
547 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
548 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
549 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
550 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
551 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
552 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
553 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
554 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
555 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
556 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
557 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
558 #ifdef ALLOW_FORCEMODELS
559 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
560 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
562 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
565 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
568 if (s == "cl_weaponpriority")
569 self.switchweapon = w_getbestweapon(self);
573 float fexists(string f)
576 fh = fopen(f, FILE_READ);
583 void backtrace(string msg)
586 dev = cvar("developer");
587 cvar_set("developer", "1");
589 dprint("--- CUT HERE ---\nWARNING: ");
592 remove(world); // isn't there any better way to cause a backtrace?
593 dprint("\n--- CUT UNTIL HERE ---\n");
594 cvar_set("developer", ftos(dev));
597 string Team_ColorCode(float teamid)
599 if (teamid == COLOR_TEAM1)
601 else if (teamid == COLOR_TEAM2)
603 else if (teamid == COLOR_TEAM3)
605 else if (teamid == COLOR_TEAM4)
610 string Team_ColorName(float t)
612 // fixme: Search for team entities and get their .netname's!
613 if (t == COLOR_TEAM1)
615 if (t == COLOR_TEAM2)
617 if (t == COLOR_TEAM3)
619 if (t == COLOR_TEAM4)
623 string Team_ColorNameLowerCase(float t)
625 // fixme: Search for team entities and get their .netname's!
626 if (t == COLOR_TEAM1)
628 if (t == COLOR_TEAM2)
630 if (t == COLOR_TEAM3)
632 if (t == COLOR_TEAM4)
637 #define CENTERPRIO_POINT 1
638 #define CENTERPRIO_SPAM 2
639 #define CENTERPRIO_VOTE 4
640 #define CENTERPRIO_NORMAL 5
641 #define CENTERPRIO_SHIELDING 7
642 #define CENTERPRIO_MAPVOTE 9
643 #define CENTERPRIO_IDLEKICK 50
644 #define CENTERPRIO_ADMIN 99
645 .float centerprint_priority;
646 .float centerprint_expires;
647 void centerprint_atprio(entity e, float prio, string s)
649 if (intermission_running)
650 if (prio < CENTERPRIO_MAPVOTE)
652 if (time > e.centerprint_expires)
653 e.centerprint_priority = 0;
654 if (prio >= e.centerprint_priority)
656 e.centerprint_priority = prio;
657 if (timeoutStatus == 2)
658 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
660 e.centerprint_expires = time + e.cvar_scr_centertime;
661 centerprint_builtin(e, s);
664 void centerprint_expire(entity e, float prio)
666 if (prio == e.centerprint_priority)
668 e.centerprint_priority = 0;
669 centerprint_builtin(e, "");
672 void centerprint(entity e, string s)
674 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
677 // decolorizes and team colors the player name when needed
678 string playername(entity p)
681 if (teams_matter && !intermission_running && p.classname == "player")
683 t = Team_ColorCode(p.team);
684 return strcat(t, strdecolorize(p.netname));
690 vector randompos(vector m1, vector m2)
694 v_x = m2_x * random() + m1_x;
695 v_y = m2_y * random() + m1_y;
696 v_z = m2_z * random() + m1_z;
700 float g_pickup_shells;
701 float g_pickup_shells_max;
702 float g_pickup_nails;
703 float g_pickup_nails_max;
704 float g_pickup_rockets;
705 float g_pickup_rockets_max;
706 float g_pickup_cells;
707 float g_pickup_cells_max;
709 float g_pickup_fuel_jetpack;
710 float g_pickup_fuel_max;
711 float g_pickup_armorsmall;
712 float g_pickup_armorsmall_max;
713 float g_pickup_armormedium;
714 float g_pickup_armormedium_max;
715 float g_pickup_armorbig;
716 float g_pickup_armorbig_max;
717 float g_pickup_armorlarge;
718 float g_pickup_armorlarge_max;
719 float g_pickup_healthsmall;
720 float g_pickup_healthsmall_max;
721 float g_pickup_healthmedium;
722 float g_pickup_healthmedium_max;
723 float g_pickup_healthlarge;
724 float g_pickup_healthlarge_max;
725 float g_pickup_healthmega;
726 float g_pickup_healthmega_max;
728 float g_weaponarena_random;
729 string g_weaponarena_list;
730 float g_weaponspeedfactor;
731 float g_weaponratefactor;
732 float g_weapondamagefactor;
733 float g_weaponforcefactor;
737 float start_ammo_shells;
738 float start_ammo_nails;
739 float start_ammo_rockets;
740 float start_ammo_cells;
741 float start_ammo_fuel;
743 float start_armorvalue;
744 float warmup_start_weapons;
745 float warmup_start_ammo_shells;
746 float warmup_start_ammo_nails;
747 float warmup_start_ammo_rockets;
748 float warmup_start_ammo_cells;
749 float warmup_start_ammo_fuel;
750 float warmup_start_health;
751 float warmup_start_armorvalue;
754 entity get_weaponinfo(float w);
756 float NixNex_CanChooseWeapon(float wpn);
757 void readplayerstartcvars()
763 // initialize starting values for players
766 start_ammo_shells = 0;
767 start_ammo_nails = 0;
768 start_ammo_rockets = 0;
769 start_ammo_cells = 0;
770 start_health = cvar("g_balance_health_start");
771 start_armorvalue = cvar("g_balance_armor_start");
774 s = cvar_string("g_weaponarena");
780 g_weaponarena_list = "All Weapons";
781 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
783 e = get_weaponinfo(j);
784 g_weaponarena |= e.weapons;
785 weapon_action(e.weapon, WR_PRECACHE);
788 else if (s == "most")
790 g_weaponarena_list = "Most Weapons";
791 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
793 e = get_weaponinfo(j);
794 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
796 g_weaponarena |= e.weapons;
797 weapon_action(e.weapon, WR_PRECACHE);
801 else if (s == "none")
803 g_weaponarena_list = "No Weapons";
804 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
808 t = tokenize_console(s);
809 g_weaponarena_list = "";
810 for (i = 0; i < t; ++i)
813 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
815 e = get_weaponinfo(j);
818 g_weaponarena |= e.weapons;
819 weapon_action(e.weapon, WR_PRECACHE);
820 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
826 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
829 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
833 g_weaponarena_random = cvar("g_weaponarena_random");
835 g_weaponarena_random = 0;
840 // will be done later
841 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
842 if (NixNex_CanChooseWeapon(i))
843 weapon_action(i, WR_PRECACHE);
844 if(!cvar("g_use_ammunition"))
845 start_items |= IT_UNLIMITED_AMMO;
847 else if (g_weaponarena)
849 start_weapons = g_weaponarena;
850 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
851 start_ammo_rockets = 999;
852 if (g_weaponarena & WEPBIT_SHOTGUN)
853 start_ammo_shells = 999;
854 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
855 start_ammo_cells = 999;
856 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
857 start_ammo_nails = 999;
858 if (g_weaponarena & WEPBIT_HOOK)
859 start_ammo_fuel = 999;
860 start_items |= IT_UNLIMITED_AMMO;
862 else if (g_minstagib)
865 start_armorvalue = 0;
866 start_weapons = WEPBIT_MINSTANEX;
867 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
868 start_ammo_cells = cvar("g_minstagib_ammo_start");
869 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
870 start_ammo_fuel = cvar("g_start_ammo_fuel");
872 if (g_minstagib_invis_alpha <= 0)
873 g_minstagib_invis_alpha = -1;
879 start_ammo_shells = cvar("g_lms_start_ammo_shells");
880 start_ammo_nails = cvar("g_lms_start_ammo_nails");
881 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
882 start_ammo_cells = cvar("g_lms_start_ammo_cells");
883 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
884 start_health = cvar("g_lms_start_health");
885 start_armorvalue = cvar("g_lms_start_armor");
887 else if (cvar("g_use_ammunition"))
889 start_ammo_shells = cvar("g_start_ammo_shells");
890 start_ammo_nails = cvar("g_start_ammo_nails");
891 start_ammo_rockets = cvar("g_start_ammo_rockets");
892 start_ammo_cells = cvar("g_start_ammo_cells");
893 start_ammo_fuel = cvar("g_start_ammo_fuel");
897 start_ammo_shells = cvar("g_pickup_shells_max");
898 start_ammo_nails = cvar("g_pickup_nails_max");
899 start_ammo_rockets = cvar("g_pickup_rockets_max");
900 start_ammo_cells = cvar("g_pickup_cells_max");
901 start_ammo_fuel = cvar("g_pickup_fuel_max");
902 start_items |= IT_UNLIMITED_AMMO;
905 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
907 e = get_weaponinfo(i);
911 t = cvar(strcat("g_start_weapon_", e.netname));
913 if (t < 0) // "default" weapon selection
916 t = (e.spawnflags & WEPSPAWNFLAG_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 if (g_nexball && i == WEP_PORTO)
932 start_weapons |= e.weapons;
933 weapon_action(e.weapon, WR_PRECACHE);
940 warmup_start_ammo_shells = start_ammo_shells;
941 warmup_start_ammo_nails = start_ammo_nails;
942 warmup_start_ammo_rockets = start_ammo_rockets;
943 warmup_start_ammo_cells = start_ammo_cells;
944 warmup_start_ammo_fuel = start_ammo_fuel;
945 warmup_start_health = start_health;
946 warmup_start_armorvalue = start_armorvalue;
947 warmup_start_weapons = start_weapons;
949 if (!g_weaponarena && !g_nixnex && !g_minstagib)
951 if (cvar("g_use_ammunition"))
953 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
954 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
955 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
956 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
957 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
959 warmup_start_health = cvar("g_warmup_start_health");
960 warmup_start_armorvalue = cvar("g_warmup_start_armor");
961 if (cvar("g_warmup_allguns"))
963 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
965 e = get_weaponinfo(i);
968 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
970 warmup_start_weapons |= e.weapons;
971 weapon_action(e.weapon, WR_PRECACHE);
978 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
980 g_grappling_hook = 0; // these two can't coexist, as they use the same button
981 start_items |= IT_FUEL_REGEN;
982 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
983 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
987 start_items |= IT_JETPACK;
989 if (g_weapon_stay == 2)
991 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
992 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
993 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
994 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
995 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
996 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
997 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
998 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
999 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1000 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1003 start_ammo_shells = max(0, start_ammo_shells);
1004 start_ammo_nails = max(0, start_ammo_nails);
1005 start_ammo_cells = max(0, start_ammo_cells);
1006 start_ammo_rockets = max(0, start_ammo_rockets);
1007 start_ammo_fuel = max(0, start_ammo_fuel);
1009 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1010 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1011 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1012 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1013 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1017 float g_bugrigs_planar_movement;
1018 float g_bugrigs_planar_movement_car_jumping;
1019 float g_bugrigs_reverse_spinning;
1020 float g_bugrigs_reverse_speeding;
1021 float g_bugrigs_reverse_stopping;
1022 float g_bugrigs_air_steering;
1023 float g_bugrigs_angle_smoothing;
1024 float g_bugrigs_friction_floor;
1025 float g_bugrigs_friction_brake;
1026 float g_bugrigs_friction_air;
1027 float g_bugrigs_accel;
1028 float g_bugrigs_speed_ref;
1029 float g_bugrigs_speed_pow;
1030 float g_bugrigs_steer;
1032 float g_touchexplode;
1033 float g_touchexplode_radius;
1034 float g_touchexplode_damage;
1035 float g_touchexplode_edgedamage;
1036 float g_touchexplode_force;
1041 void readlevelcvars(void)
1043 g_bugrigs = cvar("g_bugrigs");
1044 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1045 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1046 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1047 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1048 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1049 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1050 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1051 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1052 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1053 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1054 g_bugrigs_accel = cvar("g_bugrigs_accel");
1055 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1056 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1057 g_bugrigs_steer = cvar("g_bugrigs_steer");
1059 g_touchexplode = cvar("g_touchexplode");
1060 g_touchexplode_radius = cvar("g_touchexplode_radius");
1061 g_touchexplode_damage = cvar("g_touchexplode_damage");
1062 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1063 g_touchexplode_force = cvar("g_touchexplode_force");
1065 #ifdef ALLOW_FORCEMODELS
1066 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1068 sv_loddistance1 = cvar("sv_loddistance1");
1069 sv_loddistance2 = cvar("sv_loddistance2");
1070 if(sv_loddistance2 <= sv_loddistance1)
1071 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1072 sv_clones = cvar("sv_clones");
1073 sv_cheats = cvar("sv_cheats");
1074 sv_gentle = cvar("sv_gentle");
1075 sv_foginterval = cvar("sv_foginterval");
1076 g_cloaked = cvar("g_cloaked");
1077 g_jump_grunt = cvar("g_jump_grunt");
1078 g_footsteps = cvar("g_footsteps");
1079 g_grappling_hook = cvar("g_grappling_hook");
1080 g_jetpack = cvar("g_jetpack");
1081 g_laserguided_missile = cvar("g_laserguided_missile");
1082 g_midair = cvar("g_midair");
1083 g_minstagib = cvar("g_minstagib");
1084 g_nixnex = cvar("g_nixnex");
1085 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1086 g_norecoil = cvar("g_norecoil");
1087 g_vampire = cvar("g_vampire");
1088 g_bloodloss = cvar("g_bloodloss");
1089 sv_maxidle = cvar("sv_maxidle");
1090 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1091 sv_pogostick = cvar("sv_pogostick");
1092 sv_doublejump = cvar("sv_doublejump");
1093 g_ctf_reverse = cvar("g_ctf_reverse");
1094 sv_autotaunt = cvar("sv_autotaunt");
1095 sv_taunt = cvar("sv_taunt");
1097 inWarmupStage = cvar("g_warmup");
1098 g_warmup_limit = cvar("g_warmup_limit");
1099 g_warmup_allguns = cvar("g_warmup_allguns");
1100 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1102 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1103 inWarmupStage = 0; // these modes cannot work together, sorry
1105 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1106 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1107 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1108 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1109 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1110 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1111 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1112 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1113 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1114 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1115 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1116 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1118 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1119 if (g_nixnex) g_weaponarena = 0;
1122 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1123 g_weaponratefactor = cvar("g_weaponratefactor");
1124 g_weapondamagefactor = cvar("g_weapondamagefactor");
1125 g_weaponforcefactor = cvar("g_weaponforcefactor");
1127 g_pickup_shells = cvar("g_pickup_shells");
1128 g_pickup_shells_max = cvar("g_pickup_shells_max");
1129 g_pickup_nails = cvar("g_pickup_nails");
1130 g_pickup_nails_max = cvar("g_pickup_nails_max");
1131 g_pickup_rockets = cvar("g_pickup_rockets");
1132 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1133 g_pickup_cells = cvar("g_pickup_cells");
1134 g_pickup_cells_max = cvar("g_pickup_cells_max");
1135 g_pickup_fuel = cvar("g_pickup_fuel");
1136 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1137 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1138 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1139 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1140 g_pickup_armormedium = cvar("g_pickup_armormedium");
1141 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1142 g_pickup_armorbig = cvar("g_pickup_armorbig");
1143 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1144 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1145 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1146 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1147 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1148 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1149 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1150 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1151 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1152 g_pickup_healthmega = cvar("g_pickup_healthmega");
1153 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1155 g_pinata = cvar("g_pinata");
1157 g_weapon_stay = cvar("g_weapon_stay");
1158 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1161 if not(inWarmupStage)
1162 game_starttime = cvar("g_start_delay");
1164 readplayerstartcvars();
1168 // TODO sound pack system
1171 string precache_sound_builtin (string s) = #19;
1172 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1173 string precache_sound(string s)
1175 return precache_sound_builtin(strcat(soundpack, s));
1177 void play2(entity e, string filename)
1179 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1181 void sound(entity e, float chan, string samp, float vol, float atten)
1183 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1188 string precache_sound (string s) = #19;
1189 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1190 float precache_sound_index (string s) = #19;
1192 #define SND_VOLUME 1
1193 #define SND_ATTENUATION 2
1194 #define SND_LARGEENTITY 8
1195 #define SND_LARGESOUND 16
1197 float sound_allowed(float dest, entity e)
1199 // sounds from world may always pass
1202 if (e.classname == "body")
1204 if (e.owner && e.owner != e)
1209 // sounds to self may always pass
1210 if (dest == MSG_ONE)
1211 if (e == msg_entity)
1213 // sounds by players can be removed
1214 if (cvar("bot_sound_monopoly"))
1215 if (clienttype(e) == CLIENTTYPE_REAL)
1217 // anything else may pass
1221 void sound(entity e, float chan, string samp, float vol, float atten)
1223 if (!sound_allowed(MSG_BROADCAST, e))
1225 sound_builtin(e, chan, samp, vol, atten);
1227 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1231 if (!sound_allowed(dest, e))
1234 entno = num_for_edict(e);
1235 idx = precache_sound_index(samp);
1240 atten = floor(atten * 64);
1241 vol = floor(vol * 255);
1244 sflags |= SND_VOLUME;
1246 sflags |= SND_ATTENUATION;
1248 sflags |= SND_LARGEENTITY;
1250 sflags |= SND_LARGESOUND;
1252 WriteByte(dest, SVC_SOUND);
1253 WriteByte(dest, sflags);
1254 if (sflags & SND_VOLUME)
1255 WriteByte(dest, vol);
1256 if (sflags & SND_ATTENUATION)
1257 WriteByte(dest, atten);
1258 if (sflags & SND_LARGEENTITY)
1260 WriteShort(dest, entno);
1261 WriteByte(dest, chan);
1265 WriteShort(dest, entno * 8 + chan);
1267 if (sflags & SND_LARGESOUND)
1268 WriteShort(dest, idx);
1270 WriteByte(dest, idx);
1272 WriteCoord(dest, o_x);
1273 WriteCoord(dest, o_y);
1274 WriteCoord(dest, o_z);
1276 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1280 if (!sound_allowed(dest, e))
1283 o = e.origin + 0.5 * (e.mins + e.maxs);
1284 soundtoat(dest, e, o, chan, samp, vol, atten);
1286 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1288 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1290 void stopsoundto(float dest, entity e, float chan)
1294 if (!sound_allowed(dest, e))
1297 entno = num_for_edict(e);
1302 idx = precache_sound_index("misc/null.wav");
1303 sflags = SND_LARGEENTITY;
1305 sflags |= SND_LARGESOUND;
1306 WriteByte(dest, SVC_SOUND);
1307 WriteByte(dest, sflags);
1308 WriteShort(dest, entno);
1309 WriteByte(dest, chan);
1310 if (sflags & SND_LARGESOUND)
1311 WriteShort(dest, idx);
1313 WriteByte(dest, idx);
1314 WriteCoord(dest, e.origin_x);
1315 WriteCoord(dest, e.origin_y);
1316 WriteCoord(dest, e.origin_z);
1320 WriteByte(dest, SVC_STOPSOUND);
1321 WriteShort(dest, entno * 8 + chan);
1324 void stopsound(entity e, float chan)
1326 if (!sound_allowed(MSG_BROADCAST, e))
1329 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1330 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1333 void play2(entity e, string filename)
1335 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1337 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1340 .float announcetime;
1341 float announce(entity player, string msg)
1343 if (time > player.announcetime)
1344 if (clienttype(player) == CLIENTTYPE_REAL)
1346 player.announcetime = time + 0.8;
1352 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1353 float spamsound(entity e, float chan, string samp, float vol, float atten)
1355 if (!sound_allowed(MSG_BROADCAST, e))
1358 if (time > e.announcetime)
1360 e.announcetime = time;
1361 sound(e, chan, samp, vol, atten);
1367 void play2team(float t, string filename)
1371 if (cvar("bot_sound_monopoly"))
1374 FOR_EACH_REALPLAYER(head)
1377 play2(head, filename);
1381 void play2all(string samp)
1383 if (cvar("bot_sound_monopoly"))
1386 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1389 void PrecachePlayerSounds(string f);
1390 void precache_all_models(string pattern)
1392 float globhandle, i, n;
1395 globhandle = search_begin(pattern, TRUE, FALSE);
1398 n = search_getsize(globhandle);
1399 for (i = 0; i < n; ++i)
1401 //print(search_getfilename(globhandle, i), "\n");
1402 f = search_getfilename(globhandle, i);
1405 if(substring(f, -9,5) == "_lod1")
1407 if(substring(f, -9,5) == "_lod2")
1409 if(!sv_loddistance1)
1411 PrecachePlayerSounds(strcat(f, ".sounds"));
1413 search_end(globhandle);
1418 // gamemode related things
1419 precache_model ("models/misc/chatbubble.spr");
1420 precache_model ("models/misc/teambubble.spr");
1423 precache_model ("models/runematch/curse.mdl");
1424 precache_model ("models/runematch/rune.mdl");
1427 #ifdef TTURRETS_ENABLED
1428 if (cvar("g_turrets"))
1432 // Precache all player models if desired
1433 if (cvar("sv_precacheplayermodels"))
1435 PrecachePlayerSounds("sound/player/default.sounds");
1436 precache_all_models("models/player/*.zym");
1437 precache_all_models("models/player/*.dpm");
1438 precache_all_models("models/player/*.md3");
1439 precache_all_models("models/player/*.psk");
1440 //precache_model("models/player/carni.zym");
1441 //precache_model("models/player/crash.zym");
1442 //precache_model("models/player/grunt.zym");
1443 //precache_model("models/player/headhunter.zym");
1444 //precache_model("models/player/insurrectionist.zym");
1445 //precache_model("models/player/jeandarc.zym");
1446 //precache_model("models/player/lurk.zym");
1447 //precache_model("models/player/lycanthrope.zym");
1448 //precache_model("models/player/marine.zym");
1449 //precache_model("models/player/nexus.zym");
1450 //precache_model("models/player/pyria.zym");
1451 //precache_model("models/player/shock.zym");
1452 //precache_model("models/player/skadi.zym");
1453 //precache_model("models/player/specop.zym");
1454 //precache_model("models/player/visitant.zym");
1457 if (cvar("sv_defaultcharacter"))
1460 s = cvar_string("sv_defaultplayermodel_red");
1464 PrecachePlayerSounds(strcat(s, ".sounds"));
1466 s = cvar_string("sv_defaultplayermodel_blue");
1470 PrecachePlayerSounds(strcat(s, ".sounds"));
1472 s = cvar_string("sv_defaultplayermodel_yellow");
1476 PrecachePlayerSounds(strcat(s, ".sounds"));
1478 s = cvar_string("sv_defaultplayermodel_pink");
1482 PrecachePlayerSounds(strcat(s, ".sounds"));
1484 s = cvar_string("sv_defaultplayermodel");
1488 PrecachePlayerSounds(strcat(s, ".sounds"));
1494 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1495 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1498 // gore and miscellaneous sounds
1499 //precache_sound ("misc/h2ohit.wav");
1500 precache_model ("models/hook.md3");
1501 precache_sound ("misc/armorimpact.wav");
1502 precache_sound ("misc/bodyimpact1.wav");
1503 precache_sound ("misc/bodyimpact2.wav");
1504 precache_sound ("misc/gib.wav");
1505 precache_sound ("misc/gib_splat01.wav");
1506 precache_sound ("misc/gib_splat02.wav");
1507 precache_sound ("misc/gib_splat03.wav");
1508 precache_sound ("misc/gib_splat04.wav");
1509 precache_sound ("misc/hit.wav");
1510 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1511 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1512 precache_sound ("misc/null.wav");
1513 precache_sound ("misc/spawn.wav");
1514 precache_sound ("misc/talk.wav");
1515 precache_sound ("misc/teleport.wav");
1516 precache_sound ("misc/poweroff.wav");
1517 precache_sound ("player/lava.wav");
1518 precache_sound ("player/slime.wav");
1521 precache_sound ("misc/jetpack_fly.wav");
1523 // announcer sounds - male
1524 precache_sound ("announcer/male/electrobitch.wav");
1525 precache_sound ("announcer/male/airshot.wav");
1526 precache_sound ("announcer/male/03kills.wav");
1527 precache_sound ("announcer/male/05kills.wav");
1528 precache_sound ("announcer/male/10kills.wav");
1529 precache_sound ("announcer/male/15kills.wav");
1530 precache_sound ("announcer/male/20kills.wav");
1531 precache_sound ("announcer/male/25kills.wav");
1532 precache_sound ("announcer/male/30kills.wav");
1533 precache_sound ("announcer/male/botlike.wav");
1534 precache_sound ("announcer/male/yoda.wav");
1535 precache_sound ("announcer/male/amazing.wav");
1536 precache_sound ("announcer/male/awesome.wav");
1537 precache_sound ("announcer/male/headshot.wav");
1538 precache_sound ("announcer/male/impressive.wav");
1540 // announcer sounds - robotic
1541 precache_sound ("announcer/robotic/prepareforbattle.wav");
1542 precache_sound ("announcer/robotic/begin.wav");
1543 precache_sound ("announcer/robotic/timeoutcalled.wav");
1544 precache_sound ("announcer/robotic/1fragleft.wav");
1545 precache_sound ("announcer/robotic/2fragsleft.wav");
1546 precache_sound ("announcer/robotic/3fragsleft.wav");
1547 precache_sound ("announcer/robotic/terminated.wav");
1550 precache_sound ("announcer/robotic/lastsecond.wav");
1551 precache_sound ("announcer/robotic/narrowly.wav");
1554 precache_model ("models/sprites/0.spr32");
1555 precache_model ("models/sprites/1.spr32");
1556 precache_model ("models/sprites/2.spr32");
1557 precache_model ("models/sprites/3.spr32");
1558 precache_model ("models/sprites/4.spr32");
1559 precache_model ("models/sprites/5.spr32");
1560 precache_model ("models/sprites/6.spr32");
1561 precache_model ("models/sprites/7.spr32");
1562 precache_model ("models/sprites/8.spr32");
1563 precache_model ("models/sprites/9.spr32");
1564 precache_model ("models/sprites/10.spr32");
1565 precache_sound ("announcer/robotic/1.wav");
1566 precache_sound ("announcer/robotic/2.wav");
1567 precache_sound ("announcer/robotic/3.wav");
1568 precache_sound ("announcer/robotic/4.wav");
1569 precache_sound ("announcer/robotic/5.wav");
1570 precache_sound ("announcer/robotic/6.wav");
1571 precache_sound ("announcer/robotic/7.wav");
1572 precache_sound ("announcer/robotic/8.wav");
1573 precache_sound ("announcer/robotic/9.wav");
1574 precache_sound ("announcer/robotic/10.wav");
1576 // common weapon precaches
1577 precache_sound ("weapons/weapon_switch.wav");
1578 precache_sound ("weapons/weaponpickup.wav");
1579 precache_sound ("weapons/unavailable.wav");
1580 if (g_grappling_hook)
1582 precache_sound ("weapons/hook_fire.wav"); // hook
1583 precache_sound ("weapons/hook_impact.wav"); // hook
1586 if (cvar("sv_precacheweapons") || g_nixnex)
1588 //precache weapon models/sounds
1591 while (wep <= WEP_LAST)
1593 weapon_action(wep, WR_PRECACHE);
1598 precache_model("models/elaser.mdl");
1599 precache_model("models/laser.mdl");
1600 precache_model("models/ebomb.mdl");
1603 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1605 if (!self.noise && self.music) // quake 3 uses the music field
1606 self.noise = self.music;
1608 // plays music for the level if there is any
1611 precache_sound (self.noise);
1612 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1617 // sorry, but using \ in macros breaks line numbers
1618 #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
1619 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1620 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1622 vector ExactTriggerHit_mins;
1623 vector ExactTriggerHit_maxs;
1624 float ExactTriggerHit_Recurse()
1630 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1633 if (trace_ent == self)
1638 se.solid = SOLID_NOT;
1639 f = ExactTriggerHit_Recurse();
1645 float ExactTriggerHit()
1649 if not(self.modelindex)
1653 self.solid = SOLID_BSP;
1654 ExactTriggerHit_mins = other.absmin;
1655 ExactTriggerHit_maxs = other.absmax;
1656 f = ExactTriggerHit_Recurse();
1662 // WARNING: this kills the trace globals
1663 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1664 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1666 #define INITPRIO_FIRST 0
1667 #define INITPRIO_GAMETYPE 0
1668 #define INITPRIO_GAMETYPE_FALLBACK 1
1669 #define INITPRIO_CVARS 5
1670 #define INITPRIO_FINDTARGET 10
1671 #define INITPRIO_DROPTOFLOOR 20
1672 #define INITPRIO_SETLOCATION 90
1673 #define INITPRIO_LINKDOORS 91
1674 #define INITPRIO_LAST 99
1676 .void(void) initialize_entity;
1677 .float initialize_entity_order;
1678 .entity initialize_entity_next;
1679 entity initialize_entity_first;
1681 void make_safe_for_remove(entity e)
1683 if (e.initialize_entity)
1686 for (ent = initialize_entity_first; ent; )
1688 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1690 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1691 // skip it in linked list
1694 prev.initialize_entity_next = ent.initialize_entity_next;
1695 ent = prev.initialize_entity_next;
1699 initialize_entity_first = ent.initialize_entity_next;
1700 ent = initialize_entity_first;
1706 ent = ent.initialize_entity_next;
1712 void objerror(string s)
1714 make_safe_for_remove(self);
1715 objerror_builtin(s);
1718 void remove_unsafely(entity e)
1723 void remove_safely(entity e)
1725 make_safe_for_remove(e);
1729 void InitializeEntity(entity e, void(void) func, float order)
1733 if (!e || e.initialize_entity)
1735 // make a proxy initializer entity
1739 e.classname = "initialize_entity";
1743 e.initialize_entity = func;
1744 e.initialize_entity_order = order;
1746 cur = initialize_entity_first;
1749 if (!cur || cur.initialize_entity_order > order)
1751 // insert between prev and cur
1753 prev.initialize_entity_next = e;
1755 initialize_entity_first = e;
1756 e.initialize_entity_next = cur;
1760 cur = cur.initialize_entity_next;
1763 void InitializeEntitiesRun()
1766 startoflist = initialize_entity_first;
1767 initialize_entity_first = world;
1768 for (self = startoflist; self; )
1771 var void(void) func;
1772 e = self.initialize_entity_next;
1773 func = self.initialize_entity;
1774 self.initialize_entity_order = 0;
1775 self.initialize_entity = func_null;
1776 self.initialize_entity_next = world;
1777 if (self.classname == "initialize_entity")
1781 remove_builtin(self);
1784 //dprint("Delayed initialization: ", self.classname, "\n");
1790 .float uncustomizeentityforclient_set;
1791 .void(void) uncustomizeentityforclient;
1792 void(void) SUB_Nullpointer = #0;
1793 void UncustomizeEntitiesRun()
1797 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1798 self.uncustomizeentityforclient();
1801 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1803 e.customizeentityforclient = customizer;
1804 e.uncustomizeentityforclient = uncustomizer;
1805 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1809 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1812 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1816 if (e.classname == "")
1817 e.classname = "net_linked";
1819 if (e.model == "" || self.modelindex == 0)
1823 setmodel(e, "null");
1827 e.SendEntity = sendfunc;
1828 e.SendFlags = 0xFFFFFF;
1831 e.effects |= EF_NODEPTHTEST;
1835 e.nextthink = time + dt;
1836 e.think = SUB_Remove;
1840 void adaptor_think2touch()
1849 void adaptor_think2use()
1861 // deferred dropping
1862 void DropToFloor_Handler()
1864 droptofloor_builtin();
1865 self.dropped_origin = self.origin;
1870 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1875 float trace_hits_box_a0, trace_hits_box_a1;
1877 float trace_hits_box_1d(float end, float thmi, float thma)
1881 // just check if x is in range
1889 // do the trace with respect to x
1890 // 0 -> end has to stay in thmi -> thma
1891 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1892 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1893 if (trace_hits_box_a0 > trace_hits_box_a1)
1899 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1904 // now it is a trace from 0 to end
1906 trace_hits_box_a0 = 0;
1907 trace_hits_box_a1 = 1;
1909 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1911 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1913 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1919 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1921 return trace_hits_box(start, end, thmi - ma, thma - mi);
1924 float SUB_NoImpactCheck()
1926 // zero hitcontents = this is not the real impact, but either the
1927 // mirror-impact of something hitting the projectile instead of the
1928 // projectile hitting the something, or a touchareagrid one. Neither of
1929 // these stop the projectile from moving, so...
1930 if(trace_dphitcontents == 0)
1932 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1935 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1937 if (other == world && self.size != '0 0 0')
1940 tic = self.velocity * sys_ticrate;
1941 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1942 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1943 if (trace_fraction >= 1)
1945 dprint("Odd... did not hit...?\n");
1947 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1949 dprint("Detected and prevented the sky-grapple bug.\n");
1957 #define SUB_OwnerCheck() (other && (other == self.owner))
1959 #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)
1961 float MAX_IPBAN_URIS = 16;
1963 float URI_GET_DISCARD = 0;
1964 float URI_GET_IPBAN = 1;
1965 float URI_GET_IPBAN_END = 16;
1967 void URI_Get_Callback(float id, float status, string data)
1969 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
1971 dprint("\nEnd of data.\n");
1973 if (id == URI_GET_DISCARD)
1977 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1980 OnlineBanList_URI_Get_Callback(id, status, data);
1984 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1988 void print_to(entity e, string s)
1991 sprint(e, strcat(s, "\n"));
2010 for (i = 0; i < MapInfo_count; ++i)
2012 if (MapInfo_Get_ByID(i))
2014 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2017 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2018 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2026 for (i = 0; i < MapInfo_count; ++i)
2028 if (MapInfo_Get_ByID(i))
2030 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2033 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2034 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2042 for (i = 0; i < MapInfo_count; ++i)
2044 if (MapInfo_Get_ByID(i))
2046 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2049 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2050 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2056 MapInfo_ClearTemps();
2059 return "No records are available on this server.\n";
2061 return strcat("Records on this server:\n", s);
2064 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2067 vector start, org, delta, end, enddown, mstart;
2069 m = e.dphitcontentsmask;
2070 e.dphitcontentsmask = goodcontents | badcontents;
2073 delta = world.maxs - world.mins;
2075 for (i = 0; i < attempts; ++i)
2077 start_x = org_x + random() * delta_x;
2078 start_y = org_y + random() * delta_y;
2079 start_z = org_z + random() * delta_z;
2081 // rule 1: start inside world bounds, and outside
2082 // solid, and don't start from somewhere where you can
2083 // fall down to evil
2084 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2085 if (trace_fraction >= 1)
2087 if (trace_startsolid)
2089 if (trace_dphitcontents & badcontents)
2091 if (trace_dphitq3surfaceflags & badsurfaceflags)
2094 // rule 2: if we are too high, lower the point
2095 if (trace_fraction * delta_z > maxaboveground)
2096 start = trace_endpos + '0 0 1' * maxaboveground;
2097 enddown = trace_endpos;
2099 // rule 3: make sure we aren't outside the map. This only works
2100 // for somewhat well formed maps. A good rule of thumb is that
2101 // the map should have a convex outside hull.
2102 // these can be traceLINES as we already verified the starting box
2103 mstart = start + 0.5 * (e.mins + e.maxs);
2104 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2105 if (trace_fraction >= 1)
2107 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2108 if (trace_fraction >= 1)
2110 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2111 if (trace_fraction >= 1)
2113 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2114 if (trace_fraction >= 1)
2116 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2117 if (trace_fraction >= 1)
2120 // find a random vector to "look at"
2121 end_x = org_x + random() * delta_x;
2122 end_y = org_y + random() * delta_y;
2123 end_z = org_z + random() * delta_z;
2124 end = start + normalize(end - start) * vlen(delta);
2126 // rule 4: start TO end must not be too short
2127 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2128 if (trace_startsolid)
2130 if (trace_fraction < minviewdistance / vlen(delta))
2133 // rule 5: don't want to look at sky
2134 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2137 // rule 6: we must not end up in trigger_hurt
2138 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2140 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2147 e.dphitcontentsmask = m;
2151 setorigin(e, start);
2152 e.angles = vectoangles(end - start);
2153 dprint("Needed ", ftos(i + 1), " attempts\n");
2160 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2162 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2163 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2164 WriteShort(MSG_BROADCAST, effectno);
2165 WriteCoord(MSG_BROADCAST, start_x);
2166 WriteCoord(MSG_BROADCAST, start_y);
2167 WriteCoord(MSG_BROADCAST, start_z);
2168 WriteCoord(MSG_BROADCAST, end_x);
2169 WriteCoord(MSG_BROADCAST, end_y);
2170 WriteCoord(MSG_BROADCAST, end_z);
2171 WriteCoord(MSG_BROADCAST, end_dz);
2172 WriteShort(MSG_BROADCAST, spd / 16);
2175 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2178 vector vecxy, velxy;
2180 vecxy = end - start;
2185 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2187 trailparticles(world, effectno, start, end);
2191 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2192 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2195 string GetGametype(); // g_world.qc
2196 void write_recordmarker(entity pl, float tstart, float dt)
2198 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2200 // also write a marker into demo files for demotc-race-record-extractor to find
2203 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2204 " ", ftos(tstart), " ", ftos(dt), "\n"));
2207 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2209 switch(self.owner.cvar_cl_gunalign)
2220 if(allowcenter) // 2: allow center handedness
2233 if(allowcenter) // 2: allow center handedness
2249 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2254 if (cvar("g_shootfromeye"))
2258 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2266 else if (cvar("g_shootfromcenter"))
2270 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2278 else if (cvar("g_shootfromclient"))
2280 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2282 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2297 void attach_sameorigin(entity e, entity to, string tag)
2299 vector org, t_forward, t_left, t_up, e_forward, e_up;
2306 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2307 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2308 t_forward = v_forward * tagscale;
2309 t_left = v_right * -tagscale;
2310 t_up = v_up * tagscale;
2312 e.origin_x = org * t_forward;
2313 e.origin_y = org * t_left;
2314 e.origin_z = org * t_up;
2316 // current forward and up directions
2317 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2318 e.angles_x = -e.angles_x;
2319 fixedmakevectors(e.angles);
2321 // untransform forward, up!
2322 e_forward_x = v_forward * t_forward;
2323 e_forward_y = v_forward * t_left;
2324 e_forward_z = v_forward * t_up;
2325 e_up_x = v_up * t_forward;
2326 e_up_y = v_up * t_left;
2327 e_up_z = v_up * t_up;
2329 e.angles = fixedvectoangles2(e_forward, e_up);
2330 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2331 e.angles_x = -e.angles_x;
2333 setattachment(e, to, tag);
2334 setorigin(e, e.origin);
2337 void detach_sameorigin(entity e)
2340 org = gettaginfo(e, 0);
2341 e.angles = fixedvectoangles2(v_forward, v_up);
2342 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2343 e.angles_x = -e.angles_x;
2345 setattachment(e, world, "");
2346 setorigin(e, e.origin);
2349 void follow_sameorigin(entity e, entity to)
2351 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2352 e.aiment = to; // make the hole follow bmodel
2353 e.punchangle = to.angles; // the original angles of bmodel
2354 e.view_ofs = e.origin - to.origin; // relative origin
2355 e.v_angle = e.angles - to.angles; // relative angles
2358 void unfollow_sameorigin(entity e)
2360 e.movetype = MOVETYPE_NONE;
2363 entity gettaginfo_relative_ent;
2364 vector gettaginfo_relative(entity e, float tag)
2366 if (!gettaginfo_relative_ent)
2368 gettaginfo_relative_ent = spawn();
2369 gettaginfo_relative_ent.effects = EF_NODRAW;
2371 gettaginfo_relative_ent.model = e.model;
2372 gettaginfo_relative_ent.modelindex = e.modelindex;
2373 gettaginfo_relative_ent.frame = e.frame;
2374 return gettaginfo(gettaginfo_relative_ent, tag);
2377 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2381 if (pl.soundentity.cnt & p)
2383 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2384 pl.soundentity.cnt |= p;
2387 void SoundEntity_StopSound(entity pl, float chan)
2391 if (pl.soundentity.cnt & p)
2393 stopsoundto(MSG_ALL, pl.soundentity, chan);
2394 pl.soundentity.cnt &~= p;
2398 void SoundEntity_Attach(entity pl)
2400 pl.soundentity = spawn();
2401 pl.soundentity.classname = "soundentity";
2402 pl.soundentity.owner = pl;
2403 setattachment(pl.soundentity, pl, "");
2404 setmodel(pl.soundentity, "null");
2407 void SoundEntity_Detach(entity pl)
2410 for (i = 0; i <= 7; ++i)
2411 SoundEntity_StopSound(pl, i);
2415 float ParseCommandPlayerSlotTarget_firsttoken;
2416 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2424 ParseCommandPlayerSlotTarget_firsttoken = -1;
2428 if (substring(argv(idx), 0, 1) == "#")
2430 s = substring(argv(idx), 1, -1);
2438 ParseCommandPlayerSlotTarget_firsttoken = idx;
2439 if (s == ftos(stof(s)))
2441 e = edict_num(stof(s));
2442 if (e.flags & FL_CLIENT)
2448 // it must be a nick name
2451 ParseCommandPlayerSlotTarget_firsttoken = idx;
2454 FOR_EACH_CLIENT(head)
2455 if (head.netname == s)
2463 s = strdecolorize(s);
2465 FOR_EACH_CLIENT(head)
2466 if (strdecolorize(head.netname) == s)
2481 float modeleffect_SendEntity(entity to, float sf)
2484 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2487 if(self.velocity != '0 0 0')
2489 if(self.angles != '0 0 0')
2491 if(self.avelocity != '0 0 0')
2494 WriteByte(MSG_ENTITY, f);
2495 WriteShort(MSG_ENTITY, self.modelindex);
2496 WriteByte(MSG_ENTITY, self.skin);
2497 WriteByte(MSG_ENTITY, self.frame);
2498 WriteCoord(MSG_ENTITY, self.origin_x);
2499 WriteCoord(MSG_ENTITY, self.origin_y);
2500 WriteCoord(MSG_ENTITY, self.origin_z);
2503 WriteCoord(MSG_ENTITY, self.velocity_x);
2504 WriteCoord(MSG_ENTITY, self.velocity_y);
2505 WriteCoord(MSG_ENTITY, self.velocity_z);
2509 WriteCoord(MSG_ENTITY, self.angles_x);
2510 WriteCoord(MSG_ENTITY, self.angles_y);
2511 WriteCoord(MSG_ENTITY, self.angles_z);
2515 WriteCoord(MSG_ENTITY, self.avelocity_x);
2516 WriteCoord(MSG_ENTITY, self.avelocity_y);
2517 WriteCoord(MSG_ENTITY, self.avelocity_z);
2519 WriteShort(MSG_ENTITY, self.scale * 256.0);
2520 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2521 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2522 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2523 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2528 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)
2533 e.classname = "modeleffect";
2541 e.teleport_time = t1;
2545 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2549 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2552 sz = max(e.scale, e.scale2);
2553 setsize(e, e.mins * sz, e.maxs * sz);
2554 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2557 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2559 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2562 float randombit(float bits)
2564 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2573 for(f = 1; f <= bits; f *= 2)
2582 r = (r - 1) / (n - 1);
2589 float randombits(float bits, float k)
2593 while(k > 0 && bits != r)
2595 r += randombit(bits - r);
2601 void randombit_test(float bits, float iter)
2605 print(ftos(randombit(bits)), "\n");