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_stats")) && (enPlayer.health >= 1))
128 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
130 if(cvar("sv_fragmessage_information_ping")) {
131 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
132 strMessage = strcat(strMessage, "\n^7(^2Bot");
134 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
135 if(cvar("sv_fragmessage_information_handicap"))
136 if(cvar("sv_fragmessage_information_handicap") == 2)
137 if(nPlayerHandicap <= 1)
138 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
140 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
141 else if not(nPlayerHandicap <= 1)
142 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
144 strMessage = strcat(strMessage, "^7)");
145 } else if(cvar("sv_fragmessage_information_handicap")) {
146 if(cvar("sv_fragmessage_information_handicap") == 2)
147 if(nPlayerHandicap <= 1)
148 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
150 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
151 else if(nPlayerHandicap > 1)
152 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
156 void bcenterprint(string s)
158 // TODO replace by MSG_ALL (would show it to spectators too, though)?
160 FOR_EACH_PLAYER(head)
161 if (clienttype(head) == CLIENTTYPE_REAL)
162 centerprint(head, s);
165 void GameLogEcho(string s)
170 if (cvar("sv_eventlog_files"))
175 matches = cvar("sv_eventlog_files_counter") + 1;
176 cvar_set("sv_eventlog_files_counter", ftos(matches));
179 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
180 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
181 logfile = fopen(fn, FILE_APPEND);
182 fputs(logfile, ":logversion:3\n");
186 if (cvar("sv_eventlog_files_timestamps"))
187 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
189 fputs(logfile, strcat(s, "\n"));
192 if (cvar("sv_eventlog_console"))
201 // will be opened later
206 if (logfile_open && logfile >= 0)
213 float spawnpoint_nag;
214 void relocate_spawnpoint()
216 // nudge off the floor
217 setorigin(self, self.origin + '0 0 1');
219 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
220 if (trace_startsolid)
226 if (!move_out_of_solid(self))
227 objerror("could not get out of solid at all!");
228 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
229 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
230 print(" ", ftos(self.origin_y - o_y));
231 print(" ", ftos(self.origin_z - o_z), "'\n");
232 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
235 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
241 self.mins = self.maxs = '0 0 0';
242 objerror("player spawn point in solid, mapper sucks!\n");
247 if (cvar("g_spawnpoints_autodrop"))
249 setsize(self, PL_MIN, PL_MAX);
253 self.use = spawnpoint_use;
254 self.team_saved = self.team;
258 if (g_ctf || g_assault || g_onslaught || g_domination || g_nexball)
260 have_team_spawns = 1;
262 if (cvar("r_showbboxes"))
264 // show where spawnpoints point at too
265 makevectors(self.angles);
268 e.classname = "info_player_foo";
269 setorigin(e, self.origin + v_forward * 24);
270 setsize(e, '-8 -8 -8', '8 8 8');
271 e.solid = SOLID_TRIGGER;
275 #define strstr strstrofs
277 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
278 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
279 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
280 // BE CONSTANT OR strzoneD!
281 float strstr(string haystack, string needle, float offset)
285 len = strlen(needle);
286 endpos = strlen(haystack) - len;
287 while(offset <= endpos)
289 found = substring(haystack, offset, len);
298 float NUM_NEAREST_ENTITIES = 4;
299 entity nearest_entity[NUM_NEAREST_ENTITIES];
300 float nearest_length[NUM_NEAREST_ENTITIES];
301 entity findnearest(vector point, .string field, string value, vector axismod)
312 localhead = find(world, field, value);
315 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
316 dist = localhead.oldorigin;
318 dist = localhead.origin;
320 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
323 for (i = 0; i < num_nearest; ++i)
325 if (len < nearest_length[i])
329 // now i tells us where to insert at
330 // INSERTION SORT! YOU'VE SEEN IT! RUN!
331 if (i < NUM_NEAREST_ENTITIES)
333 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
335 nearest_length[j + 1] = nearest_length[j];
336 nearest_entity[j + 1] = nearest_entity[j];
338 nearest_length[i] = len;
339 nearest_entity[i] = localhead;
340 if (num_nearest < NUM_NEAREST_ENTITIES)
341 num_nearest = num_nearest + 1;
344 localhead = find(localhead, field, value);
347 // now use the first one from our list that we can see
348 for (i = 0; i < num_nearest; ++i)
350 traceline(point, nearest_entity[i].origin, TRUE, world);
351 if (trace_fraction == 1)
355 dprint("Nearest point (");
356 dprint(nearest_entity[0].netname);
357 dprint(") is not visible, using a visible one.\n");
359 return nearest_entity[i];
363 if (num_nearest == 0)
366 dprint("Not seeing any location point, using nearest as fallback.\n");
368 dprint("Candidates were: ");
369 for(j = 0; j < num_nearest; ++j)
373 dprint(nearest_entity[j].netname);
378 return nearest_entity[0];
381 void spawnfunc_target_location()
383 self.classname = "target_location";
384 // location name in netname
385 // eventually support: count, teamgame selectors, line of sight?
388 void spawnfunc_info_location()
390 self.classname = "target_location";
391 self.message = self.netname;
394 string NearestLocation(vector p)
399 loc = findnearest(p, classname, "target_location", '1 1 1');
406 loc = findnearest(p, target, "###item###", '1 1 4');
413 string formatmessage(string msg)
424 break; // too many replacements
426 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
427 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
437 replacement = substring(msg, p, 2);
438 escape = substring(msg, p + 1, 1);
441 else if (escape == "\\")
443 else if (escape == "n")
445 else if (escape == "a")
446 replacement = ftos(floor(self.armorvalue));
447 else if (escape == "h")
448 replacement = ftos(floor(self.health));
449 else if (escape == "l")
450 replacement = NearestLocation(self.origin);
451 else if (escape == "y")
452 replacement = NearestLocation(self.cursor_trace_endpos);
453 else if (escape == "d")
454 replacement = NearestLocation(self.death_origin);
455 else if (escape == "w")
460 wep = self.switchweapon;
463 replacement = W_Name(wep);
465 else if (escape == "W")
467 if (self.items & IT_SHELLS) replacement = "shells";
468 else if (self.items & IT_NAILS) replacement = "bullets";
469 else if (self.items & IT_ROCKETS) replacement = "rockets";
470 else if (self.items & IT_CELLS) replacement = "cells";
471 else replacement = "batteries"; // ;)
473 else if (escape == "x")
475 replacement = self.cursor_trace_ent.netname;
476 if (!replacement || !self.cursor_trace_ent)
477 replacement = "nothing";
479 else if (escape == "p")
481 if (self.last_selected_player)
482 replacement = self.last_selected_player.netname;
484 replacement = "(nobody)";
486 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
487 p = p + strlen(replacement);
498 >0: receives a cvar from name=argv(f) value=argv(f+1)
500 void GetCvars_handleString(string thisname, float f, .string field, string name)
505 strunzone(self.field);
506 self.field = string_null;
510 if (thisname == name)
513 strunzone(self.field);
514 self.field = strzone(argv(f + 1));
518 stuffcmd(self, strcat("sendcvar ", name, "\n"));
520 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
522 GetCvars_handleString(thisname, f, field, name);
523 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
524 if (thisname == name)
527 s = func(strcat1(self.field));
530 strunzone(self.field);
531 self.field = strzone(s);
535 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
542 if (thisname == name)
543 self.field = stof(argv(f + 1));
546 stuffcmd(self, strcat("sendcvar ", name, "\n"));
548 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
555 if (thisname == name)
559 self.field = stof(argv(f + 1));
568 stuffcmd(self, strcat("sendcvar ", name, "\n"));
571 string W_FixWeaponOrder_ForceComplete(string s);
572 string W_FixWeaponOrder_AllowIncomplete(string s);
573 float w_getbestweapon(entity e);
574 void GetCvars(float f)
578 s = strcat1(argv(f));
579 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
580 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
581 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
582 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
583 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
584 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
585 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
586 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
587 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
588 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
589 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
590 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
591 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
592 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
593 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
594 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
595 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
596 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
597 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
598 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
599 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
600 #ifdef ALLOW_FORCEMODELS
601 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
602 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
604 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
605 GetCvars_handleFloatOnce(s, f, cvar_cl_noantilag, "cl_noantilag");
608 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
611 if (s == "cl_weaponpriority")
612 self.switchweapon = w_getbestweapon(self);
616 float fexists(string f)
619 fh = fopen(f, FILE_READ);
626 void backtrace(string msg)
629 dev = cvar("developer");
630 war = cvar("prvm_backtraceforwarnings");
631 cvar_set("developer", "1");
632 cvar_set("prvm_backtraceforwarnings", "1");
634 dprint("--- CUT HERE ---\nWARNING: ");
637 remove(world); // isn't there any better way to cause a backtrace?
638 dprint("\n--- CUT UNTIL HERE ---\n");
639 cvar_set("developer", ftos(dev));
640 cvar_set("prvm_backtraceforwarnings", ftos(war));
643 string Team_ColorCode(float teamid)
645 if (teamid == COLOR_TEAM1)
647 else if (teamid == COLOR_TEAM2)
649 else if (teamid == COLOR_TEAM3)
651 else if (teamid == COLOR_TEAM4)
656 string Team_ColorName(float t)
658 // fixme: Search for team entities and get their .netname's!
659 if (t == COLOR_TEAM1)
661 if (t == COLOR_TEAM2)
663 if (t == COLOR_TEAM3)
665 if (t == COLOR_TEAM4)
669 string Team_ColorNameLowerCase(float t)
671 // fixme: Search for team entities and get their .netname's!
672 if (t == COLOR_TEAM1)
674 if (t == COLOR_TEAM2)
676 if (t == COLOR_TEAM3)
678 if (t == COLOR_TEAM4)
683 #define CENTERPRIO_POINT 1
684 #define CENTERPRIO_SPAM 2
685 #define CENTERPRIO_VOTE 4
686 #define CENTERPRIO_NORMAL 5
687 #define CENTERPRIO_SHIELDING 7
688 #define CENTERPRIO_MAPVOTE 9
689 #define CENTERPRIO_IDLEKICK 50
690 #define CENTERPRIO_ADMIN 99
691 .float centerprint_priority;
692 .float centerprint_expires;
693 void centerprint_atprio(entity e, float prio, string s)
695 if (intermission_running)
696 if (prio < CENTERPRIO_MAPVOTE)
698 if (time > e.centerprint_expires)
699 e.centerprint_priority = 0;
700 if (prio >= e.centerprint_priority)
702 e.centerprint_priority = prio;
703 if (timeoutStatus == 2)
704 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
706 e.centerprint_expires = time + e.cvar_scr_centertime;
707 centerprint_builtin(e, s);
710 void centerprint_expire(entity e, float prio)
712 if (prio == e.centerprint_priority)
714 e.centerprint_priority = 0;
715 centerprint_builtin(e, "");
718 void centerprint(entity e, string s)
720 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
723 // decolorizes and team colors the player name when needed
724 string playername(entity p)
727 if (teams_matter && !intermission_running && p.classname == "player")
729 t = Team_ColorCode(p.team);
730 return strcat(t, strdecolorize(p.netname));
736 vector randompos(vector m1, vector m2)
740 v_x = m2_x * random() + m1_x;
741 v_y = m2_y * random() + m1_y;
742 v_z = m2_z * random() + m1_z;
746 float g_pickup_shells;
747 float g_pickup_shells_max;
748 float g_pickup_nails;
749 float g_pickup_nails_max;
750 float g_pickup_rockets;
751 float g_pickup_rockets_max;
752 float g_pickup_cells;
753 float g_pickup_cells_max;
755 float g_pickup_fuel_jetpack;
756 float g_pickup_fuel_max;
757 float g_pickup_armorsmall;
758 float g_pickup_armorsmall_max;
759 float g_pickup_armormedium;
760 float g_pickup_armormedium_max;
761 float g_pickup_armorbig;
762 float g_pickup_armorbig_max;
763 float g_pickup_armorlarge;
764 float g_pickup_armorlarge_max;
765 float g_pickup_healthsmall;
766 float g_pickup_healthsmall_max;
767 float g_pickup_healthmedium;
768 float g_pickup_healthmedium_max;
769 float g_pickup_healthlarge;
770 float g_pickup_healthlarge_max;
771 float g_pickup_healthmega;
772 float g_pickup_healthmega_max;
774 float g_weaponarena_random;
775 string g_weaponarena_list;
776 float g_weaponspeedfactor;
777 float g_weaponratefactor;
778 float g_weapondamagefactor;
779 float g_weaponforcefactor;
783 float start_ammo_shells;
784 float start_ammo_nails;
785 float start_ammo_rockets;
786 float start_ammo_cells;
787 float start_ammo_fuel;
789 float start_armorvalue;
790 float warmup_start_weapons;
791 float warmup_start_ammo_shells;
792 float warmup_start_ammo_nails;
793 float warmup_start_ammo_rockets;
794 float warmup_start_ammo_cells;
795 float warmup_start_ammo_fuel;
796 float warmup_start_health;
797 float warmup_start_armorvalue;
801 entity get_weaponinfo(float w);
803 float NixNex_CanChooseWeapon(float wpn);
804 void readplayerstartcvars()
810 // initialize starting values for players
813 start_ammo_shells = 0;
814 start_ammo_nails = 0;
815 start_ammo_rockets = 0;
816 start_ammo_cells = 0;
817 start_health = cvar("g_balance_health_start");
818 start_armorvalue = cvar("g_balance_armor_start");
821 s = cvar_string("g_weaponarena");
827 g_weaponarena_list = "All Weapons";
828 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
830 e = get_weaponinfo(j);
831 g_weaponarena |= e.weapons;
832 weapon_action(e.weapon, WR_PRECACHE);
835 else if (s == "most")
837 g_weaponarena_list = "Most Weapons";
838 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
840 e = get_weaponinfo(j);
841 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
843 g_weaponarena |= e.weapons;
844 weapon_action(e.weapon, WR_PRECACHE);
848 else if (s == "none")
850 g_weaponarena_list = "No Weapons";
851 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
855 t = tokenize_console(s);
856 g_weaponarena_list = "";
857 for (i = 0; i < t; ++i)
860 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
862 e = get_weaponinfo(j);
865 g_weaponarena |= e.weapons;
866 weapon_action(e.weapon, WR_PRECACHE);
867 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
873 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
876 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
880 g_weaponarena_random = cvar("g_weaponarena_random");
882 g_weaponarena_random = 0;
887 // will be done later
888 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
889 if (NixNex_CanChooseWeapon(i))
890 weapon_action(i, WR_PRECACHE);
891 if(!cvar("g_use_ammunition"))
892 start_items |= IT_UNLIMITED_AMMO;
894 else if (g_weaponarena)
896 start_weapons = g_weaponarena;
897 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
898 start_ammo_rockets = 999;
899 if (g_weaponarena & WEPBIT_SHOTGUN)
900 start_ammo_shells = 999;
901 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
902 start_ammo_cells = 999;
903 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
904 start_ammo_nails = 999;
905 if (g_weaponarena & WEPBIT_HOOK)
906 start_ammo_fuel = 999;
907 start_items |= IT_UNLIMITED_AMMO;
909 else if (g_minstagib)
912 start_armorvalue = 0;
913 start_weapons = WEPBIT_MINSTANEX;
914 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
915 start_ammo_cells = cvar("g_minstagib_ammo_start");
916 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
917 start_ammo_fuel = cvar("g_start_ammo_fuel");
919 if (g_minstagib_invis_alpha <= 0)
920 g_minstagib_invis_alpha = -1;
926 start_ammo_shells = cvar("g_lms_start_ammo_shells");
927 start_ammo_nails = cvar("g_lms_start_ammo_nails");
928 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
929 start_ammo_cells = cvar("g_lms_start_ammo_cells");
930 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
931 start_health = cvar("g_lms_start_health");
932 start_armorvalue = cvar("g_lms_start_armor");
934 else if (cvar("g_use_ammunition"))
936 start_ammo_shells = cvar("g_start_ammo_shells");
937 start_ammo_nails = cvar("g_start_ammo_nails");
938 start_ammo_rockets = cvar("g_start_ammo_rockets");
939 start_ammo_cells = cvar("g_start_ammo_cells");
940 start_ammo_fuel = cvar("g_start_ammo_fuel");
944 start_ammo_shells = cvar("g_pickup_shells_max");
945 start_ammo_nails = cvar("g_pickup_nails_max");
946 start_ammo_rockets = cvar("g_pickup_rockets_max");
947 start_ammo_cells = cvar("g_pickup_cells_max");
948 start_ammo_fuel = cvar("g_pickup_fuel_max");
949 start_items |= IT_UNLIMITED_AMMO;
952 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
954 e = get_weaponinfo(i);
958 t = cvar(strcat("g_start_weapon_", e.netname));
960 if (t < 0) // "default" weapon selection
963 t = (e.spawnflags & WEPSPAWNFLAG_NORMAL);
964 else if (g_race || g_cts)
965 t = (i == WEP_LASER);
967 t = 0; // weapon is set a few lines later
969 t = (i == WEP_LASER || i == WEP_SHOTGUN);
970 if (g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
971 t += (i == WEP_HOOK);
974 if (g_nexball && i == WEP_PORTO)
979 start_weapons |= e.weapons;
980 weapon_action(e.weapon, WR_PRECACHE);
987 warmup_start_ammo_shells = start_ammo_shells;
988 warmup_start_ammo_nails = start_ammo_nails;
989 warmup_start_ammo_rockets = start_ammo_rockets;
990 warmup_start_ammo_cells = start_ammo_cells;
991 warmup_start_ammo_fuel = start_ammo_fuel;
992 warmup_start_health = start_health;
993 warmup_start_armorvalue = start_armorvalue;
994 warmup_start_weapons = start_weapons;
996 if (!g_weaponarena && !g_nixnex && !g_minstagib)
998 if (cvar("g_use_ammunition"))
1000 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1001 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1002 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1003 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1004 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1006 warmup_start_health = cvar("g_warmup_start_health");
1007 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1008 if (cvar("g_warmup_allguns"))
1010 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1012 e = get_weaponinfo(i);
1015 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
1017 warmup_start_weapons |= e.weapons;
1018 weapon_action(e.weapon, WR_PRECACHE);
1025 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1027 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1028 start_items |= IT_FUEL_REGEN;
1029 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1030 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1034 start_items |= IT_JETPACK;
1036 if (g_weapon_stay == 2)
1038 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1039 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1040 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1041 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1042 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1043 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1044 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1045 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1046 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1047 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1050 start_ammo_shells = max(0, start_ammo_shells);
1051 start_ammo_nails = max(0, start_ammo_nails);
1052 start_ammo_cells = max(0, start_ammo_cells);
1053 start_ammo_rockets = max(0, start_ammo_rockets);
1054 start_ammo_fuel = max(0, start_ammo_fuel);
1056 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1057 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1058 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1059 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1060 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1064 float g_bugrigs_planar_movement;
1065 float g_bugrigs_planar_movement_car_jumping;
1066 float g_bugrigs_reverse_spinning;
1067 float g_bugrigs_reverse_speeding;
1068 float g_bugrigs_reverse_stopping;
1069 float g_bugrigs_air_steering;
1070 float g_bugrigs_angle_smoothing;
1071 float g_bugrigs_friction_floor;
1072 float g_bugrigs_friction_brake;
1073 float g_bugrigs_friction_air;
1074 float g_bugrigs_accel;
1075 float g_bugrigs_speed_ref;
1076 float g_bugrigs_speed_pow;
1077 float g_bugrigs_steer;
1079 float g_touchexplode;
1080 float g_touchexplode_radius;
1081 float g_touchexplode_damage;
1082 float g_touchexplode_edgedamage;
1083 float g_touchexplode_force;
1090 float sv_pitch_fixyaw;
1092 void readlevelcvars(void)
1094 g_bugrigs = cvar("g_bugrigs");
1095 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1096 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1097 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1098 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1099 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1100 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1101 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1102 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1103 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1104 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1105 g_bugrigs_accel = cvar("g_bugrigs_accel");
1106 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1107 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1108 g_bugrigs_steer = cvar("g_bugrigs_steer");
1110 g_touchexplode = cvar("g_touchexplode");
1111 g_touchexplode_radius = cvar("g_touchexplode_radius");
1112 g_touchexplode_damage = cvar("g_touchexplode_damage");
1113 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1114 g_touchexplode_force = cvar("g_touchexplode_force");
1116 #ifdef ALLOW_FORCEMODELS
1117 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1119 sv_loddistance1 = cvar("sv_loddistance1");
1120 sv_loddistance2 = cvar("sv_loddistance2");
1121 if(sv_loddistance2 <= sv_loddistance1)
1122 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1123 sv_clones = cvar("sv_clones");
1124 sv_cheats = cvar("sv_cheats");
1125 sv_gentle = cvar("sv_gentle");
1126 sv_foginterval = cvar("sv_foginterval");
1127 g_cloaked = cvar("g_cloaked");
1128 g_jump_grunt = cvar("g_jump_grunt");
1129 g_footsteps = cvar("g_footsteps");
1130 g_grappling_hook = cvar("g_grappling_hook");
1131 g_jetpack = cvar("g_jetpack");
1132 g_laserguided_missile = cvar("g_laserguided_missile");
1133 g_midair = cvar("g_midair");
1134 g_minstagib = cvar("g_minstagib");
1135 g_nixnex = cvar("g_nixnex");
1136 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1137 g_norecoil = cvar("g_norecoil");
1138 g_vampire = cvar("g_vampire");
1139 g_bloodloss = cvar("g_bloodloss");
1140 sv_maxidle = cvar("sv_maxidle");
1141 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1142 sv_pogostick = cvar("sv_pogostick");
1143 sv_doublejump = cvar("sv_doublejump");
1144 g_ctf_reverse = cvar("g_ctf_reverse");
1145 sv_autotaunt = cvar("sv_autotaunt");
1146 sv_taunt = cvar("sv_taunt");
1148 inWarmupStage = cvar("g_warmup");
1149 g_warmup_limit = cvar("g_warmup_limit");
1150 g_warmup_allguns = cvar("g_warmup_allguns");
1151 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1153 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1154 inWarmupStage = 0; // these modes cannot work together, sorry
1156 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1157 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1158 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1159 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1160 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1161 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1162 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1163 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1164 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1165 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1166 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1167 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1169 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1170 if (g_nixnex) g_weaponarena = 0;
1173 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1174 g_weaponratefactor = cvar("g_weaponratefactor");
1175 g_weapondamagefactor = cvar("g_weapondamagefactor");
1176 g_weaponforcefactor = cvar("g_weaponforcefactor");
1178 g_pickup_shells = cvar("g_pickup_shells");
1179 g_pickup_shells_max = cvar("g_pickup_shells_max");
1180 g_pickup_nails = cvar("g_pickup_nails");
1181 g_pickup_nails_max = cvar("g_pickup_nails_max");
1182 g_pickup_rockets = cvar("g_pickup_rockets");
1183 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1184 g_pickup_cells = cvar("g_pickup_cells");
1185 g_pickup_cells_max = cvar("g_pickup_cells_max");
1186 g_pickup_fuel = cvar("g_pickup_fuel");
1187 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1188 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1189 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1190 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1191 g_pickup_armormedium = cvar("g_pickup_armormedium");
1192 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1193 g_pickup_armorbig = cvar("g_pickup_armorbig");
1194 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1195 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1196 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1197 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1198 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1199 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1200 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1201 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1202 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1203 g_pickup_healthmega = cvar("g_pickup_healthmega");
1204 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1206 g_pinata = cvar("g_pinata");
1208 g_weapon_stay = cvar("g_weapon_stay");
1209 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1211 g_ghost_items = cvar("g_ghost_items");
1212 if(g_ghost_items >= 1)
1213 g_ghost_items = 0.13; // default alpha value
1215 if not(inWarmupStage)
1216 game_starttime = cvar("g_start_delay");
1218 sv_pitch_min = cvar("sv_pitch_min");
1219 sv_pitch_max = cvar("sv_pitch_max");
1220 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1222 readplayerstartcvars();
1226 // TODO sound pack system
1229 string precache_sound_builtin (string s) = #19;
1230 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1231 string precache_sound(string s)
1233 return precache_sound_builtin(strcat(soundpack, s));
1235 void play2(entity e, string filename)
1237 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1239 void sound(entity e, float chan, string samp, float vol, float atten)
1241 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1246 string precache_sound (string s) = #19;
1247 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1248 float precache_sound_index (string s) = #19;
1250 #define SND_VOLUME 1
1251 #define SND_ATTENUATION 2
1252 #define SND_LARGEENTITY 8
1253 #define SND_LARGESOUND 16
1255 float sound_allowed(float dest, entity e)
1257 // sounds from world may always pass
1260 if (e.classname == "body")
1262 if (e.owner && e.owner != e)
1267 // sounds to self may always pass
1268 if (dest == MSG_ONE)
1269 if (e == msg_entity)
1271 // sounds by players can be removed
1272 if (cvar("bot_sound_monopoly"))
1273 if (clienttype(e) == CLIENTTYPE_REAL)
1275 // anything else may pass
1279 void sound(entity e, float chan, string samp, float vol, float atten)
1281 if (!sound_allowed(MSG_BROADCAST, e))
1283 sound_builtin(e, chan, samp, vol, atten);
1285 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1289 if (!sound_allowed(dest, e))
1292 entno = num_for_edict(e);
1293 idx = precache_sound_index(samp);
1298 atten = floor(atten * 64);
1299 vol = floor(vol * 255);
1302 sflags |= SND_VOLUME;
1304 sflags |= SND_ATTENUATION;
1306 sflags |= SND_LARGEENTITY;
1308 sflags |= SND_LARGESOUND;
1310 WriteByte(dest, SVC_SOUND);
1311 WriteByte(dest, sflags);
1312 if (sflags & SND_VOLUME)
1313 WriteByte(dest, vol);
1314 if (sflags & SND_ATTENUATION)
1315 WriteByte(dest, atten);
1316 if (sflags & SND_LARGEENTITY)
1318 WriteShort(dest, entno);
1319 WriteByte(dest, chan);
1323 WriteShort(dest, entno * 8 + chan);
1325 if (sflags & SND_LARGESOUND)
1326 WriteShort(dest, idx);
1328 WriteByte(dest, idx);
1330 WriteCoord(dest, o_x);
1331 WriteCoord(dest, o_y);
1332 WriteCoord(dest, o_z);
1334 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1338 if (!sound_allowed(dest, e))
1341 o = e.origin + 0.5 * (e.mins + e.maxs);
1342 soundtoat(dest, e, o, chan, samp, vol, atten);
1344 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1346 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1348 void stopsoundto(float dest, entity e, float chan)
1352 if (!sound_allowed(dest, e))
1355 entno = num_for_edict(e);
1360 idx = precache_sound_index("misc/null.wav");
1361 sflags = SND_LARGEENTITY;
1363 sflags |= SND_LARGESOUND;
1364 WriteByte(dest, SVC_SOUND);
1365 WriteByte(dest, sflags);
1366 WriteShort(dest, entno);
1367 WriteByte(dest, chan);
1368 if (sflags & SND_LARGESOUND)
1369 WriteShort(dest, idx);
1371 WriteByte(dest, idx);
1372 WriteCoord(dest, e.origin_x);
1373 WriteCoord(dest, e.origin_y);
1374 WriteCoord(dest, e.origin_z);
1378 WriteByte(dest, SVC_STOPSOUND);
1379 WriteShort(dest, entno * 8 + chan);
1382 void stopsound(entity e, float chan)
1384 if (!sound_allowed(MSG_BROADCAST, e))
1387 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1388 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1391 void play2(entity e, string filename)
1393 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1395 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1398 .float announcetime;
1399 float announce(entity player, string msg)
1401 if (time > player.announcetime)
1402 if (clienttype(player) == CLIENTTYPE_REAL)
1404 player.announcetime = time + 0.8;
1410 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1411 float spamsound(entity e, float chan, string samp, float vol, float atten)
1413 if (!sound_allowed(MSG_BROADCAST, e))
1416 if (time > e.announcetime)
1418 e.announcetime = time;
1419 sound(e, chan, samp, vol, atten);
1425 void play2team(float t, string filename)
1429 if (cvar("bot_sound_monopoly"))
1432 FOR_EACH_REALPLAYER(head)
1435 play2(head, filename);
1439 void play2all(string samp)
1441 if (cvar("bot_sound_monopoly"))
1444 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1447 void PrecachePlayerSounds(string f);
1448 void precache_all_models(string pattern)
1450 float globhandle, i, n;
1453 globhandle = search_begin(pattern, TRUE, FALSE);
1456 n = search_getsize(globhandle);
1457 for (i = 0; i < n; ++i)
1459 //print(search_getfilename(globhandle, i), "\n");
1460 f = search_getfilename(globhandle, i);
1463 if(substring(f, -9,5) == "_lod1")
1465 if(substring(f, -9,5) == "_lod2")
1467 if(!sv_loddistance1)
1469 PrecachePlayerSounds(strcat(f, ".sounds"));
1471 search_end(globhandle);
1476 // gamemode related things
1477 precache_model ("models/misc/chatbubble.spr");
1478 precache_model ("models/misc/teambubble.spr");
1481 precache_model ("models/runematch/curse.mdl");
1482 precache_model ("models/runematch/rune.mdl");
1485 #ifdef TTURRETS_ENABLED
1486 if (cvar("g_turrets"))
1490 // Precache all player models if desired
1491 if (cvar("sv_precacheplayermodels"))
1493 PrecachePlayerSounds("sound/player/default.sounds");
1494 precache_all_models("models/player/*.zym");
1495 precache_all_models("models/player/*.dpm");
1496 precache_all_models("models/player/*.md3");
1497 precache_all_models("models/player/*.psk");
1498 //precache_model("models/player/carni.zym");
1499 //precache_model("models/player/crash.zym");
1500 //precache_model("models/player/grunt.zym");
1501 //precache_model("models/player/headhunter.zym");
1502 //precache_model("models/player/insurrectionist.zym");
1503 //precache_model("models/player/jeandarc.zym");
1504 //precache_model("models/player/lurk.zym");
1505 //precache_model("models/player/lycanthrope.zym");
1506 //precache_model("models/player/marine.zym");
1507 //precache_model("models/player/nexus.zym");
1508 //precache_model("models/player/pyria.zym");
1509 //precache_model("models/player/shock.zym");
1510 //precache_model("models/player/skadi.zym");
1511 //precache_model("models/player/specop.zym");
1512 //precache_model("models/player/visitant.zym");
1515 if (cvar("sv_defaultcharacter"))
1518 s = cvar_string("sv_defaultplayermodel_red");
1522 PrecachePlayerSounds(strcat(s, ".sounds"));
1524 s = cvar_string("sv_defaultplayermodel_blue");
1528 PrecachePlayerSounds(strcat(s, ".sounds"));
1530 s = cvar_string("sv_defaultplayermodel_yellow");
1534 PrecachePlayerSounds(strcat(s, ".sounds"));
1536 s = cvar_string("sv_defaultplayermodel_pink");
1540 PrecachePlayerSounds(strcat(s, ".sounds"));
1542 s = cvar_string("sv_defaultplayermodel");
1546 PrecachePlayerSounds(strcat(s, ".sounds"));
1552 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1553 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1556 // gore and miscellaneous sounds
1557 //precache_sound ("misc/h2ohit.wav");
1558 precache_model ("models/hook.md3");
1559 precache_sound ("misc/armorimpact.wav");
1560 precache_sound ("misc/bodyimpact1.wav");
1561 precache_sound ("misc/bodyimpact2.wav");
1562 precache_sound ("misc/gib.wav");
1563 precache_sound ("misc/gib_splat01.wav");
1564 precache_sound ("misc/gib_splat02.wav");
1565 precache_sound ("misc/gib_splat03.wav");
1566 precache_sound ("misc/gib_splat04.wav");
1567 precache_sound ("misc/hit.wav");
1568 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1569 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1570 precache_sound ("misc/null.wav");
1571 precache_sound ("misc/spawn.wav");
1572 precache_sound ("misc/talk.wav");
1573 precache_sound ("misc/teleport.wav");
1574 precache_sound ("misc/poweroff.wav");
1575 precache_sound ("player/lava.wav");
1576 precache_sound ("player/slime.wav");
1579 precache_sound ("misc/jetpack_fly.wav");
1581 // announcer sounds - male
1582 precache_sound ("announcer/male/electrobitch.wav");
1583 precache_sound ("announcer/male/airshot.wav");
1584 precache_sound ("announcer/male/03kills.wav");
1585 precache_sound ("announcer/male/05kills.wav");
1586 precache_sound ("announcer/male/10kills.wav");
1587 precache_sound ("announcer/male/15kills.wav");
1588 precache_sound ("announcer/male/20kills.wav");
1589 precache_sound ("announcer/male/25kills.wav");
1590 precache_sound ("announcer/male/30kills.wav");
1591 precache_sound ("announcer/male/botlike.wav");
1592 precache_sound ("announcer/male/yoda.wav");
1593 precache_sound ("announcer/male/amazing.wav");
1594 precache_sound ("announcer/male/awesome.wav");
1595 precache_sound ("announcer/male/headshot.wav");
1596 precache_sound ("announcer/male/impressive.wav");
1598 // announcer sounds - robotic
1599 precache_sound ("announcer/robotic/prepareforbattle.wav");
1600 precache_sound ("announcer/robotic/begin.wav");
1601 precache_sound ("announcer/robotic/timeoutcalled.wav");
1602 precache_sound ("announcer/robotic/1fragleft.wav");
1603 precache_sound ("announcer/robotic/2fragsleft.wav");
1604 precache_sound ("announcer/robotic/3fragsleft.wav");
1605 precache_sound ("announcer/robotic/terminated.wav");
1608 precache_sound ("announcer/robotic/lastsecond.wav");
1609 precache_sound ("announcer/robotic/narrowly.wav");
1612 precache_model ("models/sprites/0.spr32");
1613 precache_model ("models/sprites/1.spr32");
1614 precache_model ("models/sprites/2.spr32");
1615 precache_model ("models/sprites/3.spr32");
1616 precache_model ("models/sprites/4.spr32");
1617 precache_model ("models/sprites/5.spr32");
1618 precache_model ("models/sprites/6.spr32");
1619 precache_model ("models/sprites/7.spr32");
1620 precache_model ("models/sprites/8.spr32");
1621 precache_model ("models/sprites/9.spr32");
1622 precache_model ("models/sprites/10.spr32");
1623 precache_sound ("announcer/robotic/1.wav");
1624 precache_sound ("announcer/robotic/2.wav");
1625 precache_sound ("announcer/robotic/3.wav");
1626 precache_sound ("announcer/robotic/4.wav");
1627 precache_sound ("announcer/robotic/5.wav");
1628 precache_sound ("announcer/robotic/6.wav");
1629 precache_sound ("announcer/robotic/7.wav");
1630 precache_sound ("announcer/robotic/8.wav");
1631 precache_sound ("announcer/robotic/9.wav");
1632 precache_sound ("announcer/robotic/10.wav");
1634 // common weapon precaches
1635 precache_sound ("weapons/weapon_switch.wav");
1636 precache_sound ("weapons/weaponpickup.wav");
1637 precache_sound ("weapons/unavailable.wav");
1638 if (g_grappling_hook)
1640 precache_sound ("weapons/hook_fire.wav"); // hook
1641 precache_sound ("weapons/hook_impact.wav"); // hook
1644 if (cvar("sv_precacheweapons") || g_nixnex)
1646 //precache weapon models/sounds
1649 while (wep <= WEP_LAST)
1651 weapon_action(wep, WR_PRECACHE);
1656 precache_model("models/elaser.mdl");
1657 precache_model("models/laser.mdl");
1658 precache_model("models/ebomb.mdl");
1661 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1663 if (!self.noise && self.music) // quake 3 uses the music field
1664 self.noise = self.music;
1666 // plays music for the level if there is any
1669 precache_sound (self.noise);
1670 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1675 // sorry, but using \ in macros breaks line numbers
1676 #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
1677 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1678 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1680 vector ExactTriggerHit_mins;
1681 vector ExactTriggerHit_maxs;
1682 float ExactTriggerHit_Recurse()
1688 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1691 if (trace_ent == self)
1696 se.solid = SOLID_NOT;
1697 f = ExactTriggerHit_Recurse();
1703 float ExactTriggerHit()
1707 if not(self.modelindex)
1711 self.solid = SOLID_BSP;
1712 ExactTriggerHit_mins = other.absmin;
1713 ExactTriggerHit_maxs = other.absmax;
1714 f = ExactTriggerHit_Recurse();
1720 // WARNING: this kills the trace globals
1721 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1722 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1724 #define INITPRIO_FIRST 0
1725 #define INITPRIO_GAMETYPE 0
1726 #define INITPRIO_GAMETYPE_FALLBACK 1
1727 #define INITPRIO_CVARS 5
1728 #define INITPRIO_FINDTARGET 10
1729 #define INITPRIO_DROPTOFLOOR 20
1730 #define INITPRIO_SETLOCATION 90
1731 #define INITPRIO_LINKDOORS 91
1732 #define INITPRIO_LAST 99
1734 .void(void) initialize_entity;
1735 .float initialize_entity_order;
1736 .entity initialize_entity_next;
1737 entity initialize_entity_first;
1739 void make_safe_for_remove(entity e)
1741 if (e.initialize_entity)
1744 for (ent = initialize_entity_first; ent; )
1746 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1748 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1749 // skip it in linked list
1752 prev.initialize_entity_next = ent.initialize_entity_next;
1753 ent = prev.initialize_entity_next;
1757 initialize_entity_first = ent.initialize_entity_next;
1758 ent = initialize_entity_first;
1764 ent = ent.initialize_entity_next;
1770 void objerror(string s)
1772 make_safe_for_remove(self);
1773 objerror_builtin(s);
1776 void remove_unsafely(entity e)
1781 void remove_safely(entity e)
1783 make_safe_for_remove(e);
1787 void InitializeEntity(entity e, void(void) func, float order)
1791 if (!e || e.initialize_entity)
1793 // make a proxy initializer entity
1797 e.classname = "initialize_entity";
1801 e.initialize_entity = func;
1802 e.initialize_entity_order = order;
1804 cur = initialize_entity_first;
1807 if (!cur || cur.initialize_entity_order > order)
1809 // insert between prev and cur
1811 prev.initialize_entity_next = e;
1813 initialize_entity_first = e;
1814 e.initialize_entity_next = cur;
1818 cur = cur.initialize_entity_next;
1821 void InitializeEntitiesRun()
1824 startoflist = initialize_entity_first;
1825 initialize_entity_first = world;
1826 for (self = startoflist; self; )
1829 var void(void) func;
1830 e = self.initialize_entity_next;
1831 func = self.initialize_entity;
1832 self.initialize_entity_order = 0;
1833 self.initialize_entity = func_null;
1834 self.initialize_entity_next = world;
1835 if (self.classname == "initialize_entity")
1839 remove_builtin(self);
1842 //dprint("Delayed initialization: ", self.classname, "\n");
1848 .float uncustomizeentityforclient_set;
1849 .void(void) uncustomizeentityforclient;
1850 void(void) SUB_Nullpointer = #0;
1851 void UncustomizeEntitiesRun()
1855 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1856 self.uncustomizeentityforclient();
1859 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1861 e.customizeentityforclient = customizer;
1862 e.uncustomizeentityforclient = uncustomizer;
1863 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1867 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1870 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1874 if (e.classname == "")
1875 e.classname = "net_linked";
1877 if (e.model == "" || self.modelindex == 0)
1881 setmodel(e, "null");
1885 e.SendEntity = sendfunc;
1886 e.SendFlags = 0xFFFFFF;
1889 e.effects |= EF_NODEPTHTEST;
1893 e.nextthink = time + dt;
1894 e.think = SUB_Remove;
1898 void adaptor_think2touch()
1907 void adaptor_think2use()
1919 // deferred dropping
1920 void DropToFloor_Handler()
1922 droptofloor_builtin();
1923 self.dropped_origin = self.origin;
1928 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1933 float trace_hits_box_a0, trace_hits_box_a1;
1935 float trace_hits_box_1d(float end, float thmi, float thma)
1939 // just check if x is in range
1947 // do the trace with respect to x
1948 // 0 -> end has to stay in thmi -> thma
1949 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1950 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1951 if (trace_hits_box_a0 > trace_hits_box_a1)
1957 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1962 // now it is a trace from 0 to end
1964 trace_hits_box_a0 = 0;
1965 trace_hits_box_a1 = 1;
1967 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1969 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1971 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1977 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1979 return trace_hits_box(start, end, thmi - ma, thma - mi);
1982 float SUB_NoImpactCheck()
1984 // zero hitcontents = this is not the real impact, but either the
1985 // mirror-impact of something hitting the projectile instead of the
1986 // projectile hitting the something, or a touchareagrid one. Neither of
1987 // these stop the projectile from moving, so...
1988 if(trace_dphitcontents == 0)
1990 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1993 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1995 if (other == world && self.size != '0 0 0')
1998 tic = self.velocity * sys_ticrate;
1999 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
2000 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
2001 if (trace_fraction >= 1)
2003 dprint("Odd... did not hit...?\n");
2005 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2007 dprint("Detected and prevented the sky-grapple bug.\n");
2015 #define SUB_OwnerCheck() (other && (other == self.owner))
2017 #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)
2019 float MAX_IPBAN_URIS = 16;
2021 float URI_GET_DISCARD = 0;
2022 float URI_GET_IPBAN = 1;
2023 float URI_GET_IPBAN_END = 16;
2025 void URI_Get_Callback(float id, float status, string data)
2027 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2029 dprint("\nEnd of data.\n");
2031 if (id == URI_GET_DISCARD)
2035 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2038 OnlineBanList_URI_Get_Callback(id, status, data);
2042 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2046 void print_to(entity e, string s)
2049 sprint(e, strcat(s, "\n"));
2068 for (i = 0; i < MapInfo_count; ++i)
2070 if (MapInfo_Get_ByID(i))
2072 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2075 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2076 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2084 for (i = 0; i < MapInfo_count; ++i)
2086 if (MapInfo_Get_ByID(i))
2088 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2091 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2092 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2100 for (i = 0; i < MapInfo_count; ++i)
2102 if (MapInfo_Get_ByID(i))
2104 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2107 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2108 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2114 MapInfo_ClearTemps();
2117 return "No records are available on this server.\n";
2119 return strcat("Records on this server:\n", s);
2122 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2125 vector start, org, delta, end, enddown, mstart;
2127 m = e.dphitcontentsmask;
2128 e.dphitcontentsmask = goodcontents | badcontents;
2131 delta = world.maxs - world.mins;
2133 for (i = 0; i < attempts; ++i)
2135 start_x = org_x + random() * delta_x;
2136 start_y = org_y + random() * delta_y;
2137 start_z = org_z + random() * delta_z;
2139 // rule 1: start inside world bounds, and outside
2140 // solid, and don't start from somewhere where you can
2141 // fall down to evil
2142 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2143 if (trace_fraction >= 1)
2145 if (trace_startsolid)
2147 if (trace_dphitcontents & badcontents)
2149 if (trace_dphitq3surfaceflags & badsurfaceflags)
2152 // rule 2: if we are too high, lower the point
2153 if (trace_fraction * delta_z > maxaboveground)
2154 start = trace_endpos + '0 0 1' * maxaboveground;
2155 enddown = trace_endpos;
2157 // rule 3: make sure we aren't outside the map. This only works
2158 // for somewhat well formed maps. A good rule of thumb is that
2159 // the map should have a convex outside hull.
2160 // these can be traceLINES as we already verified the starting box
2161 mstart = start + 0.5 * (e.mins + e.maxs);
2162 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2163 if (trace_fraction >= 1)
2165 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2166 if (trace_fraction >= 1)
2168 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2169 if (trace_fraction >= 1)
2171 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2172 if (trace_fraction >= 1)
2174 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2175 if (trace_fraction >= 1)
2178 // find a random vector to "look at"
2179 end_x = org_x + random() * delta_x;
2180 end_y = org_y + random() * delta_y;
2181 end_z = org_z + random() * delta_z;
2182 end = start + normalize(end - start) * vlen(delta);
2184 // rule 4: start TO end must not be too short
2185 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2186 if (trace_startsolid)
2188 if (trace_fraction < minviewdistance / vlen(delta))
2191 // rule 5: don't want to look at sky
2192 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2195 // rule 6: we must not end up in trigger_hurt
2196 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2198 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2205 e.dphitcontentsmask = m;
2209 setorigin(e, start);
2210 e.angles = vectoangles(end - start);
2211 dprint("Needed ", ftos(i + 1), " attempts\n");
2218 float zcurveparticles_effectno;
2219 vector zcurveparticles_start;
2220 float zcurveparticles_spd;
2222 void endzcurveparticles()
2224 if(zcurveparticles_effectno)
2227 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2229 zcurveparticles_effectno = 0;
2232 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2234 spd = bound(0, floor(spd / 16), 32767);
2235 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2237 endzcurveparticles();
2238 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2239 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2240 WriteShort(MSG_BROADCAST, effectno);
2241 WriteCoord(MSG_BROADCAST, start_x);
2242 WriteCoord(MSG_BROADCAST, start_y);
2243 WriteCoord(MSG_BROADCAST, start_z);
2244 zcurveparticles_effectno = effectno;
2245 zcurveparticles_start = start;
2248 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2249 WriteCoord(MSG_BROADCAST, end_x);
2250 WriteCoord(MSG_BROADCAST, end_y);
2251 WriteCoord(MSG_BROADCAST, end_z);
2252 WriteCoord(MSG_BROADCAST, end_dz);
2253 zcurveparticles_spd = spd;
2256 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2259 vector vecxy, velxy;
2261 vecxy = end - start;
2266 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2268 endzcurveparticles();
2269 trailparticles(world, effectno, start, end);
2273 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2274 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2277 string GetGametype(); // g_world.qc
2278 void write_recordmarker(entity pl, float tstart, float dt)
2280 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2282 // also write a marker into demo files for demotc-race-record-extractor to find
2285 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2286 " ", ftos(tstart), " ", ftos(dt), "\n"));
2289 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2291 switch(self.owner.cvar_cl_gunalign)
2302 if(allowcenter) // 2: allow center handedness
2315 if(allowcenter) // 2: allow center handedness
2331 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2336 if (cvar("g_shootfromeye"))
2340 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2348 else if (cvar("g_shootfromcenter"))
2352 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2360 else if (cvar("g_shootfromclient"))
2362 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2364 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2379 void attach_sameorigin(entity e, entity to, string tag)
2381 vector org, t_forward, t_left, t_up, e_forward, e_up;
2388 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2389 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2390 t_forward = v_forward * tagscale;
2391 t_left = v_right * -tagscale;
2392 t_up = v_up * tagscale;
2394 e.origin_x = org * t_forward;
2395 e.origin_y = org * t_left;
2396 e.origin_z = org * t_up;
2398 // current forward and up directions
2399 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2400 e.angles_x = -e.angles_x;
2401 fixedmakevectors(e.angles);
2403 // untransform forward, up!
2404 e_forward_x = v_forward * t_forward;
2405 e_forward_y = v_forward * t_left;
2406 e_forward_z = v_forward * t_up;
2407 e_up_x = v_up * t_forward;
2408 e_up_y = v_up * t_left;
2409 e_up_z = v_up * t_up;
2411 e.angles = fixedvectoangles2(e_forward, e_up);
2412 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2413 e.angles_x = -e.angles_x;
2415 setattachment(e, to, tag);
2416 setorigin(e, e.origin);
2419 void detach_sameorigin(entity e)
2422 org = gettaginfo(e, 0);
2423 e.angles = fixedvectoangles2(v_forward, v_up);
2424 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2425 e.angles_x = -e.angles_x;
2427 setattachment(e, world, "");
2428 setorigin(e, e.origin);
2431 void follow_sameorigin(entity e, entity to)
2433 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2434 e.aiment = to; // make the hole follow bmodel
2435 e.punchangle = to.angles; // the original angles of bmodel
2436 e.view_ofs = e.origin - to.origin; // relative origin
2437 e.v_angle = e.angles - to.angles; // relative angles
2440 void unfollow_sameorigin(entity e)
2442 e.movetype = MOVETYPE_NONE;
2445 entity gettaginfo_relative_ent;
2446 vector gettaginfo_relative(entity e, float tag)
2448 if (!gettaginfo_relative_ent)
2450 gettaginfo_relative_ent = spawn();
2451 gettaginfo_relative_ent.effects = EF_NODRAW;
2453 gettaginfo_relative_ent.model = e.model;
2454 gettaginfo_relative_ent.modelindex = e.modelindex;
2455 gettaginfo_relative_ent.frame = e.frame;
2456 return gettaginfo(gettaginfo_relative_ent, tag);
2459 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2463 if (pl.soundentity.cnt & p)
2465 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2466 pl.soundentity.cnt |= p;
2469 void SoundEntity_StopSound(entity pl, float chan)
2473 if (pl.soundentity.cnt & p)
2475 stopsoundto(MSG_ALL, pl.soundentity, chan);
2476 pl.soundentity.cnt &~= p;
2480 void SoundEntity_Attach(entity pl)
2482 pl.soundentity = spawn();
2483 pl.soundentity.classname = "soundentity";
2484 pl.soundentity.owner = pl;
2485 setattachment(pl.soundentity, pl, "");
2486 setmodel(pl.soundentity, "null");
2489 void SoundEntity_Detach(entity pl)
2492 for (i = 0; i <= 7; ++i)
2493 SoundEntity_StopSound(pl, i);
2497 float ParseCommandPlayerSlotTarget_firsttoken;
2498 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2506 ParseCommandPlayerSlotTarget_firsttoken = -1;
2510 if (substring(argv(idx), 0, 1) == "#")
2512 s = substring(argv(idx), 1, -1);
2520 ParseCommandPlayerSlotTarget_firsttoken = idx;
2521 if (s == ftos(stof(s)))
2523 e = edict_num(stof(s));
2524 if (e.flags & FL_CLIENT)
2530 // it must be a nick name
2533 ParseCommandPlayerSlotTarget_firsttoken = idx;
2536 FOR_EACH_CLIENT(head)
2537 if (head.netname == s)
2545 s = strdecolorize(s);
2547 FOR_EACH_CLIENT(head)
2548 if (strdecolorize(head.netname) == s)
2563 float modeleffect_SendEntity(entity to, float sf)
2566 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2569 if(self.velocity != '0 0 0')
2571 if(self.angles != '0 0 0')
2573 if(self.avelocity != '0 0 0')
2576 WriteByte(MSG_ENTITY, f);
2577 WriteShort(MSG_ENTITY, self.modelindex);
2578 WriteByte(MSG_ENTITY, self.skin);
2579 WriteByte(MSG_ENTITY, self.frame);
2580 WriteCoord(MSG_ENTITY, self.origin_x);
2581 WriteCoord(MSG_ENTITY, self.origin_y);
2582 WriteCoord(MSG_ENTITY, self.origin_z);
2585 WriteCoord(MSG_ENTITY, self.velocity_x);
2586 WriteCoord(MSG_ENTITY, self.velocity_y);
2587 WriteCoord(MSG_ENTITY, self.velocity_z);
2591 WriteCoord(MSG_ENTITY, self.angles_x);
2592 WriteCoord(MSG_ENTITY, self.angles_y);
2593 WriteCoord(MSG_ENTITY, self.angles_z);
2597 WriteCoord(MSG_ENTITY, self.avelocity_x);
2598 WriteCoord(MSG_ENTITY, self.avelocity_y);
2599 WriteCoord(MSG_ENTITY, self.avelocity_z);
2601 WriteShort(MSG_ENTITY, self.scale * 256.0);
2602 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2603 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2604 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2605 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2610 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)
2615 e.classname = "modeleffect";
2623 e.teleport_time = t1;
2627 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2631 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2634 sz = max(e.scale, e.scale2);
2635 setsize(e, e.mins * sz, e.maxs * sz);
2636 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2639 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2641 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2644 float randombit(float bits)
2646 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2655 for(f = 1; f <= bits; f *= 2)
2664 r = (r - 1) / (n - 1);
2671 float randombits(float bits, float k, float error_return)
2675 while(k > 0 && bits != r)
2677 r += randombit(bits - r);
2686 void randombit_test(float bits, float iter)
2690 print(ftos(randombit(bits)), "\n");
2695 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2697 if(halflifedist > 0)
2698 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2699 else if(halflifedist < 0)
2700 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);