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;
1088 void readlevelcvars(void)
1090 g_bugrigs = cvar("g_bugrigs");
1091 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1092 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1093 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1094 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1095 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1096 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1097 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1098 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1099 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1100 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1101 g_bugrigs_accel = cvar("g_bugrigs_accel");
1102 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1103 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1104 g_bugrigs_steer = cvar("g_bugrigs_steer");
1106 g_touchexplode = cvar("g_touchexplode");
1107 g_touchexplode_radius = cvar("g_touchexplode_radius");
1108 g_touchexplode_damage = cvar("g_touchexplode_damage");
1109 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1110 g_touchexplode_force = cvar("g_touchexplode_force");
1112 #ifdef ALLOW_FORCEMODELS
1113 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1115 sv_loddistance1 = cvar("sv_loddistance1");
1116 sv_loddistance2 = cvar("sv_loddistance2");
1117 if(sv_loddistance2 <= sv_loddistance1)
1118 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1119 sv_clones = cvar("sv_clones");
1120 sv_cheats = cvar("sv_cheats");
1121 sv_gentle = cvar("sv_gentle");
1122 sv_foginterval = cvar("sv_foginterval");
1123 g_cloaked = cvar("g_cloaked");
1124 g_jump_grunt = cvar("g_jump_grunt");
1125 g_footsteps = cvar("g_footsteps");
1126 g_grappling_hook = cvar("g_grappling_hook");
1127 g_jetpack = cvar("g_jetpack");
1128 g_laserguided_missile = cvar("g_laserguided_missile");
1129 g_midair = cvar("g_midair");
1130 g_minstagib = cvar("g_minstagib");
1131 g_nixnex = cvar("g_nixnex");
1132 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1133 g_norecoil = cvar("g_norecoil");
1134 g_vampire = cvar("g_vampire");
1135 g_bloodloss = cvar("g_bloodloss");
1136 sv_maxidle = cvar("sv_maxidle");
1137 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1138 sv_pogostick = cvar("sv_pogostick");
1139 sv_doublejump = cvar("sv_doublejump");
1140 g_ctf_reverse = cvar("g_ctf_reverse");
1141 sv_autotaunt = cvar("sv_autotaunt");
1142 sv_taunt = cvar("sv_taunt");
1144 inWarmupStage = cvar("g_warmup");
1145 g_warmup_limit = cvar("g_warmup_limit");
1146 g_warmup_allguns = cvar("g_warmup_allguns");
1147 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1149 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1150 inWarmupStage = 0; // these modes cannot work together, sorry
1152 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1153 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1154 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1155 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1156 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1157 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1158 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1159 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1160 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1161 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1162 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1163 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1165 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1166 if (g_nixnex) g_weaponarena = 0;
1169 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1170 g_weaponratefactor = cvar("g_weaponratefactor");
1171 g_weapondamagefactor = cvar("g_weapondamagefactor");
1172 g_weaponforcefactor = cvar("g_weaponforcefactor");
1174 g_pickup_shells = cvar("g_pickup_shells");
1175 g_pickup_shells_max = cvar("g_pickup_shells_max");
1176 g_pickup_nails = cvar("g_pickup_nails");
1177 g_pickup_nails_max = cvar("g_pickup_nails_max");
1178 g_pickup_rockets = cvar("g_pickup_rockets");
1179 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1180 g_pickup_cells = cvar("g_pickup_cells");
1181 g_pickup_cells_max = cvar("g_pickup_cells_max");
1182 g_pickup_fuel = cvar("g_pickup_fuel");
1183 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1184 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1185 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1186 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1187 g_pickup_armormedium = cvar("g_pickup_armormedium");
1188 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1189 g_pickup_armorbig = cvar("g_pickup_armorbig");
1190 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1191 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1192 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1193 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1194 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1195 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1196 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1197 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1198 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1199 g_pickup_healthmega = cvar("g_pickup_healthmega");
1200 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1202 g_pinata = cvar("g_pinata");
1204 g_weapon_stay = cvar("g_weapon_stay");
1205 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1207 g_ghost_items = cvar("g_ghost_items");
1208 if(g_ghost_items >= 1)
1209 g_ghost_items = 0.13; // default alpha value
1211 if not(inWarmupStage)
1212 game_starttime = cvar("g_start_delay");
1214 readplayerstartcvars();
1218 // TODO sound pack system
1221 string precache_sound_builtin (string s) = #19;
1222 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1223 string precache_sound(string s)
1225 return precache_sound_builtin(strcat(soundpack, s));
1227 void play2(entity e, string filename)
1229 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1231 void sound(entity e, float chan, string samp, float vol, float atten)
1233 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1238 string precache_sound (string s) = #19;
1239 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1240 float precache_sound_index (string s) = #19;
1242 #define SND_VOLUME 1
1243 #define SND_ATTENUATION 2
1244 #define SND_LARGEENTITY 8
1245 #define SND_LARGESOUND 16
1247 float sound_allowed(float dest, entity e)
1249 // sounds from world may always pass
1252 if (e.classname == "body")
1254 if (e.owner && e.owner != e)
1259 // sounds to self may always pass
1260 if (dest == MSG_ONE)
1261 if (e == msg_entity)
1263 // sounds by players can be removed
1264 if (cvar("bot_sound_monopoly"))
1265 if (clienttype(e) == CLIENTTYPE_REAL)
1267 // anything else may pass
1271 void sound(entity e, float chan, string samp, float vol, float atten)
1273 if (!sound_allowed(MSG_BROADCAST, e))
1275 sound_builtin(e, chan, samp, vol, atten);
1277 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1281 if (!sound_allowed(dest, e))
1284 entno = num_for_edict(e);
1285 idx = precache_sound_index(samp);
1290 atten = floor(atten * 64);
1291 vol = floor(vol * 255);
1294 sflags |= SND_VOLUME;
1296 sflags |= SND_ATTENUATION;
1298 sflags |= SND_LARGEENTITY;
1300 sflags |= SND_LARGESOUND;
1302 WriteByte(dest, SVC_SOUND);
1303 WriteByte(dest, sflags);
1304 if (sflags & SND_VOLUME)
1305 WriteByte(dest, vol);
1306 if (sflags & SND_ATTENUATION)
1307 WriteByte(dest, atten);
1308 if (sflags & SND_LARGEENTITY)
1310 WriteShort(dest, entno);
1311 WriteByte(dest, chan);
1315 WriteShort(dest, entno * 8 + chan);
1317 if (sflags & SND_LARGESOUND)
1318 WriteShort(dest, idx);
1320 WriteByte(dest, idx);
1322 WriteCoord(dest, o_x);
1323 WriteCoord(dest, o_y);
1324 WriteCoord(dest, o_z);
1326 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1330 if (!sound_allowed(dest, e))
1333 o = e.origin + 0.5 * (e.mins + e.maxs);
1334 soundtoat(dest, e, o, chan, samp, vol, atten);
1336 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1338 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1340 void stopsoundto(float dest, entity e, float chan)
1344 if (!sound_allowed(dest, e))
1347 entno = num_for_edict(e);
1352 idx = precache_sound_index("misc/null.wav");
1353 sflags = SND_LARGEENTITY;
1355 sflags |= SND_LARGESOUND;
1356 WriteByte(dest, SVC_SOUND);
1357 WriteByte(dest, sflags);
1358 WriteShort(dest, entno);
1359 WriteByte(dest, chan);
1360 if (sflags & SND_LARGESOUND)
1361 WriteShort(dest, idx);
1363 WriteByte(dest, idx);
1364 WriteCoord(dest, e.origin_x);
1365 WriteCoord(dest, e.origin_y);
1366 WriteCoord(dest, e.origin_z);
1370 WriteByte(dest, SVC_STOPSOUND);
1371 WriteShort(dest, entno * 8 + chan);
1374 void stopsound(entity e, float chan)
1376 if (!sound_allowed(MSG_BROADCAST, e))
1379 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1380 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1383 void play2(entity e, string filename)
1385 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1387 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1390 .float announcetime;
1391 float announce(entity player, string msg)
1393 if (time > player.announcetime)
1394 if (clienttype(player) == CLIENTTYPE_REAL)
1396 player.announcetime = time + 0.8;
1402 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1403 float spamsound(entity e, float chan, string samp, float vol, float atten)
1405 if (!sound_allowed(MSG_BROADCAST, e))
1408 if (time > e.announcetime)
1410 e.announcetime = time;
1411 sound(e, chan, samp, vol, atten);
1417 void play2team(float t, string filename)
1421 if (cvar("bot_sound_monopoly"))
1424 FOR_EACH_REALPLAYER(head)
1427 play2(head, filename);
1431 void play2all(string samp)
1433 if (cvar("bot_sound_monopoly"))
1436 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1439 void PrecachePlayerSounds(string f);
1440 void precache_all_models(string pattern)
1442 float globhandle, i, n;
1445 globhandle = search_begin(pattern, TRUE, FALSE);
1448 n = search_getsize(globhandle);
1449 for (i = 0; i < n; ++i)
1451 //print(search_getfilename(globhandle, i), "\n");
1452 f = search_getfilename(globhandle, i);
1455 if(substring(f, -9,5) == "_lod1")
1457 if(substring(f, -9,5) == "_lod2")
1459 if(!sv_loddistance1)
1461 PrecachePlayerSounds(strcat(f, ".sounds"));
1463 search_end(globhandle);
1468 // gamemode related things
1469 precache_model ("models/misc/chatbubble.spr");
1470 precache_model ("models/misc/teambubble.spr");
1473 precache_model ("models/runematch/curse.mdl");
1474 precache_model ("models/runematch/rune.mdl");
1477 #ifdef TTURRETS_ENABLED
1478 if (cvar("g_turrets"))
1482 // Precache all player models if desired
1483 if (cvar("sv_precacheplayermodels"))
1485 PrecachePlayerSounds("sound/player/default.sounds");
1486 precache_all_models("models/player/*.zym");
1487 precache_all_models("models/player/*.dpm");
1488 precache_all_models("models/player/*.md3");
1489 precache_all_models("models/player/*.psk");
1490 //precache_model("models/player/carni.zym");
1491 //precache_model("models/player/crash.zym");
1492 //precache_model("models/player/grunt.zym");
1493 //precache_model("models/player/headhunter.zym");
1494 //precache_model("models/player/insurrectionist.zym");
1495 //precache_model("models/player/jeandarc.zym");
1496 //precache_model("models/player/lurk.zym");
1497 //precache_model("models/player/lycanthrope.zym");
1498 //precache_model("models/player/marine.zym");
1499 //precache_model("models/player/nexus.zym");
1500 //precache_model("models/player/pyria.zym");
1501 //precache_model("models/player/shock.zym");
1502 //precache_model("models/player/skadi.zym");
1503 //precache_model("models/player/specop.zym");
1504 //precache_model("models/player/visitant.zym");
1507 if (cvar("sv_defaultcharacter"))
1510 s = cvar_string("sv_defaultplayermodel_red");
1514 PrecachePlayerSounds(strcat(s, ".sounds"));
1516 s = cvar_string("sv_defaultplayermodel_blue");
1520 PrecachePlayerSounds(strcat(s, ".sounds"));
1522 s = cvar_string("sv_defaultplayermodel_yellow");
1526 PrecachePlayerSounds(strcat(s, ".sounds"));
1528 s = cvar_string("sv_defaultplayermodel_pink");
1532 PrecachePlayerSounds(strcat(s, ".sounds"));
1534 s = cvar_string("sv_defaultplayermodel");
1538 PrecachePlayerSounds(strcat(s, ".sounds"));
1544 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1545 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1548 // gore and miscellaneous sounds
1549 //precache_sound ("misc/h2ohit.wav");
1550 precache_model ("models/hook.md3");
1551 precache_sound ("misc/armorimpact.wav");
1552 precache_sound ("misc/bodyimpact1.wav");
1553 precache_sound ("misc/bodyimpact2.wav");
1554 precache_sound ("misc/gib.wav");
1555 precache_sound ("misc/gib_splat01.wav");
1556 precache_sound ("misc/gib_splat02.wav");
1557 precache_sound ("misc/gib_splat03.wav");
1558 precache_sound ("misc/gib_splat04.wav");
1559 precache_sound ("misc/hit.wav");
1560 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1561 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1562 precache_sound ("misc/null.wav");
1563 precache_sound ("misc/spawn.wav");
1564 precache_sound ("misc/talk.wav");
1565 precache_sound ("misc/teleport.wav");
1566 precache_sound ("misc/poweroff.wav");
1567 precache_sound ("player/lava.wav");
1568 precache_sound ("player/slime.wav");
1571 precache_sound ("misc/jetpack_fly.wav");
1573 // announcer sounds - male
1574 precache_sound ("announcer/male/electrobitch.wav");
1575 precache_sound ("announcer/male/airshot.wav");
1576 precache_sound ("announcer/male/03kills.wav");
1577 precache_sound ("announcer/male/05kills.wav");
1578 precache_sound ("announcer/male/10kills.wav");
1579 precache_sound ("announcer/male/15kills.wav");
1580 precache_sound ("announcer/male/20kills.wav");
1581 precache_sound ("announcer/male/25kills.wav");
1582 precache_sound ("announcer/male/30kills.wav");
1583 precache_sound ("announcer/male/botlike.wav");
1584 precache_sound ("announcer/male/yoda.wav");
1585 precache_sound ("announcer/male/amazing.wav");
1586 precache_sound ("announcer/male/awesome.wav");
1587 precache_sound ("announcer/male/headshot.wav");
1588 precache_sound ("announcer/male/impressive.wav");
1590 // announcer sounds - robotic
1591 precache_sound ("announcer/robotic/prepareforbattle.wav");
1592 precache_sound ("announcer/robotic/begin.wav");
1593 precache_sound ("announcer/robotic/timeoutcalled.wav");
1594 precache_sound ("announcer/robotic/1fragleft.wav");
1595 precache_sound ("announcer/robotic/2fragsleft.wav");
1596 precache_sound ("announcer/robotic/3fragsleft.wav");
1597 precache_sound ("announcer/robotic/terminated.wav");
1600 precache_sound ("announcer/robotic/lastsecond.wav");
1601 precache_sound ("announcer/robotic/narrowly.wav");
1604 precache_model ("models/sprites/0.spr32");
1605 precache_model ("models/sprites/1.spr32");
1606 precache_model ("models/sprites/2.spr32");
1607 precache_model ("models/sprites/3.spr32");
1608 precache_model ("models/sprites/4.spr32");
1609 precache_model ("models/sprites/5.spr32");
1610 precache_model ("models/sprites/6.spr32");
1611 precache_model ("models/sprites/7.spr32");
1612 precache_model ("models/sprites/8.spr32");
1613 precache_model ("models/sprites/9.spr32");
1614 precache_model ("models/sprites/10.spr32");
1615 precache_sound ("announcer/robotic/1.wav");
1616 precache_sound ("announcer/robotic/2.wav");
1617 precache_sound ("announcer/robotic/3.wav");
1618 precache_sound ("announcer/robotic/4.wav");
1619 precache_sound ("announcer/robotic/5.wav");
1620 precache_sound ("announcer/robotic/6.wav");
1621 precache_sound ("announcer/robotic/7.wav");
1622 precache_sound ("announcer/robotic/8.wav");
1623 precache_sound ("announcer/robotic/9.wav");
1624 precache_sound ("announcer/robotic/10.wav");
1626 // common weapon precaches
1627 precache_sound ("weapons/weapon_switch.wav");
1628 precache_sound ("weapons/weaponpickup.wav");
1629 precache_sound ("weapons/unavailable.wav");
1630 if (g_grappling_hook)
1632 precache_sound ("weapons/hook_fire.wav"); // hook
1633 precache_sound ("weapons/hook_impact.wav"); // hook
1636 if (cvar("sv_precacheweapons") || g_nixnex)
1638 //precache weapon models/sounds
1641 while (wep <= WEP_LAST)
1643 weapon_action(wep, WR_PRECACHE);
1648 precache_model("models/elaser.mdl");
1649 precache_model("models/laser.mdl");
1650 precache_model("models/ebomb.mdl");
1653 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1655 if (!self.noise && self.music) // quake 3 uses the music field
1656 self.noise = self.music;
1658 // plays music for the level if there is any
1661 precache_sound (self.noise);
1662 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1667 // sorry, but using \ in macros breaks line numbers
1668 #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
1669 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1670 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1672 vector ExactTriggerHit_mins;
1673 vector ExactTriggerHit_maxs;
1674 float ExactTriggerHit_Recurse()
1680 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1683 if (trace_ent == self)
1688 se.solid = SOLID_NOT;
1689 f = ExactTriggerHit_Recurse();
1695 float ExactTriggerHit()
1699 if not(self.modelindex)
1703 self.solid = SOLID_BSP;
1704 ExactTriggerHit_mins = other.absmin;
1705 ExactTriggerHit_maxs = other.absmax;
1706 f = ExactTriggerHit_Recurse();
1712 // WARNING: this kills the trace globals
1713 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1714 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1716 #define INITPRIO_FIRST 0
1717 #define INITPRIO_GAMETYPE 0
1718 #define INITPRIO_GAMETYPE_FALLBACK 1
1719 #define INITPRIO_CVARS 5
1720 #define INITPRIO_FINDTARGET 10
1721 #define INITPRIO_DROPTOFLOOR 20
1722 #define INITPRIO_SETLOCATION 90
1723 #define INITPRIO_LINKDOORS 91
1724 #define INITPRIO_LAST 99
1726 .void(void) initialize_entity;
1727 .float initialize_entity_order;
1728 .entity initialize_entity_next;
1729 entity initialize_entity_first;
1731 void make_safe_for_remove(entity e)
1733 if (e.initialize_entity)
1736 for (ent = initialize_entity_first; ent; )
1738 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1740 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1741 // skip it in linked list
1744 prev.initialize_entity_next = ent.initialize_entity_next;
1745 ent = prev.initialize_entity_next;
1749 initialize_entity_first = ent.initialize_entity_next;
1750 ent = initialize_entity_first;
1756 ent = ent.initialize_entity_next;
1762 void objerror(string s)
1764 make_safe_for_remove(self);
1765 objerror_builtin(s);
1768 void remove_unsafely(entity e)
1773 void remove_safely(entity e)
1775 make_safe_for_remove(e);
1779 void InitializeEntity(entity e, void(void) func, float order)
1783 if (!e || e.initialize_entity)
1785 // make a proxy initializer entity
1789 e.classname = "initialize_entity";
1793 e.initialize_entity = func;
1794 e.initialize_entity_order = order;
1796 cur = initialize_entity_first;
1799 if (!cur || cur.initialize_entity_order > order)
1801 // insert between prev and cur
1803 prev.initialize_entity_next = e;
1805 initialize_entity_first = e;
1806 e.initialize_entity_next = cur;
1810 cur = cur.initialize_entity_next;
1813 void InitializeEntitiesRun()
1816 startoflist = initialize_entity_first;
1817 initialize_entity_first = world;
1818 for (self = startoflist; self; )
1821 var void(void) func;
1822 e = self.initialize_entity_next;
1823 func = self.initialize_entity;
1824 self.initialize_entity_order = 0;
1825 self.initialize_entity = func_null;
1826 self.initialize_entity_next = world;
1827 if (self.classname == "initialize_entity")
1831 remove_builtin(self);
1834 //dprint("Delayed initialization: ", self.classname, "\n");
1840 .float uncustomizeentityforclient_set;
1841 .void(void) uncustomizeentityforclient;
1842 void(void) SUB_Nullpointer = #0;
1843 void UncustomizeEntitiesRun()
1847 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1848 self.uncustomizeentityforclient();
1851 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1853 e.customizeentityforclient = customizer;
1854 e.uncustomizeentityforclient = uncustomizer;
1855 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1859 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1862 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1866 if (e.classname == "")
1867 e.classname = "net_linked";
1869 if (e.model == "" || self.modelindex == 0)
1873 setmodel(e, "null");
1877 e.SendEntity = sendfunc;
1878 e.SendFlags = 0xFFFFFF;
1881 e.effects |= EF_NODEPTHTEST;
1885 e.nextthink = time + dt;
1886 e.think = SUB_Remove;
1890 void adaptor_think2touch()
1899 void adaptor_think2use()
1911 // deferred dropping
1912 void DropToFloor_Handler()
1914 droptofloor_builtin();
1915 self.dropped_origin = self.origin;
1920 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1925 float trace_hits_box_a0, trace_hits_box_a1;
1927 float trace_hits_box_1d(float end, float thmi, float thma)
1931 // just check if x is in range
1939 // do the trace with respect to x
1940 // 0 -> end has to stay in thmi -> thma
1941 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1942 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1943 if (trace_hits_box_a0 > trace_hits_box_a1)
1949 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1954 // now it is a trace from 0 to end
1956 trace_hits_box_a0 = 0;
1957 trace_hits_box_a1 = 1;
1959 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1961 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1963 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1969 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1971 return trace_hits_box(start, end, thmi - ma, thma - mi);
1974 float SUB_NoImpactCheck()
1976 // zero hitcontents = this is not the real impact, but either the
1977 // mirror-impact of something hitting the projectile instead of the
1978 // projectile hitting the something, or a touchareagrid one. Neither of
1979 // these stop the projectile from moving, so...
1980 if(trace_dphitcontents == 0)
1982 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1985 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1987 if (other == world && self.size != '0 0 0')
1990 tic = self.velocity * sys_ticrate;
1991 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1992 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1993 if (trace_fraction >= 1)
1995 dprint("Odd... did not hit...?\n");
1997 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1999 dprint("Detected and prevented the sky-grapple bug.\n");
2007 #define SUB_OwnerCheck() (other && (other == self.owner))
2009 #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)
2011 float MAX_IPBAN_URIS = 16;
2013 float URI_GET_DISCARD = 0;
2014 float URI_GET_IPBAN = 1;
2015 float URI_GET_IPBAN_END = 16;
2017 void URI_Get_Callback(float id, float status, string data)
2019 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2021 dprint("\nEnd of data.\n");
2023 if (id == URI_GET_DISCARD)
2027 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2030 OnlineBanList_URI_Get_Callback(id, status, data);
2034 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2038 void print_to(entity e, string s)
2041 sprint(e, strcat(s, "\n"));
2060 for (i = 0; i < MapInfo_count; ++i)
2062 if (MapInfo_Get_ByID(i))
2064 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2067 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2068 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2076 for (i = 0; i < MapInfo_count; ++i)
2078 if (MapInfo_Get_ByID(i))
2080 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2083 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2084 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2092 for (i = 0; i < MapInfo_count; ++i)
2094 if (MapInfo_Get_ByID(i))
2096 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2099 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2100 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2106 MapInfo_ClearTemps();
2109 return "No records are available on this server.\n";
2111 return strcat("Records on this server:\n", s);
2114 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2117 vector start, org, delta, end, enddown, mstart;
2119 m = e.dphitcontentsmask;
2120 e.dphitcontentsmask = goodcontents | badcontents;
2123 delta = world.maxs - world.mins;
2125 for (i = 0; i < attempts; ++i)
2127 start_x = org_x + random() * delta_x;
2128 start_y = org_y + random() * delta_y;
2129 start_z = org_z + random() * delta_z;
2131 // rule 1: start inside world bounds, and outside
2132 // solid, and don't start from somewhere where you can
2133 // fall down to evil
2134 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2135 if (trace_fraction >= 1)
2137 if (trace_startsolid)
2139 if (trace_dphitcontents & badcontents)
2141 if (trace_dphitq3surfaceflags & badsurfaceflags)
2144 // rule 2: if we are too high, lower the point
2145 if (trace_fraction * delta_z > maxaboveground)
2146 start = trace_endpos + '0 0 1' * maxaboveground;
2147 enddown = trace_endpos;
2149 // rule 3: make sure we aren't outside the map. This only works
2150 // for somewhat well formed maps. A good rule of thumb is that
2151 // the map should have a convex outside hull.
2152 // these can be traceLINES as we already verified the starting box
2153 mstart = start + 0.5 * (e.mins + e.maxs);
2154 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2155 if (trace_fraction >= 1)
2157 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2158 if (trace_fraction >= 1)
2160 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2161 if (trace_fraction >= 1)
2163 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2164 if (trace_fraction >= 1)
2166 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2167 if (trace_fraction >= 1)
2170 // find a random vector to "look at"
2171 end_x = org_x + random() * delta_x;
2172 end_y = org_y + random() * delta_y;
2173 end_z = org_z + random() * delta_z;
2174 end = start + normalize(end - start) * vlen(delta);
2176 // rule 4: start TO end must not be too short
2177 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2178 if (trace_startsolid)
2180 if (trace_fraction < minviewdistance / vlen(delta))
2183 // rule 5: don't want to look at sky
2184 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2187 // rule 6: we must not end up in trigger_hurt
2188 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2190 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2197 e.dphitcontentsmask = m;
2201 setorigin(e, start);
2202 e.angles = vectoangles(end - start);
2203 dprint("Needed ", ftos(i + 1), " attempts\n");
2210 float zcurveparticles_effectno;
2211 vector zcurveparticles_start;
2212 float zcurveparticles_spd;
2214 void endzcurveparticles()
2216 if(zcurveparticles_effectno)
2219 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2221 zcurveparticles_effectno = 0;
2224 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2226 spd = bound(0, floor(spd / 16), 32767);
2227 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2229 endzcurveparticles();
2230 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2231 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2232 WriteShort(MSG_BROADCAST, effectno);
2233 WriteCoord(MSG_BROADCAST, start_x);
2234 WriteCoord(MSG_BROADCAST, start_y);
2235 WriteCoord(MSG_BROADCAST, start_z);
2236 zcurveparticles_effectno = effectno;
2237 zcurveparticles_start = start;
2240 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2241 WriteCoord(MSG_BROADCAST, end_x);
2242 WriteCoord(MSG_BROADCAST, end_y);
2243 WriteCoord(MSG_BROADCAST, end_z);
2244 WriteCoord(MSG_BROADCAST, end_dz);
2245 zcurveparticles_spd = spd;
2248 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2251 vector vecxy, velxy;
2253 vecxy = end - start;
2258 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2260 endzcurveparticles();
2261 trailparticles(world, effectno, start, end);
2265 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2266 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2269 string GetGametype(); // g_world.qc
2270 void write_recordmarker(entity pl, float tstart, float dt)
2272 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2274 // also write a marker into demo files for demotc-race-record-extractor to find
2277 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2278 " ", ftos(tstart), " ", ftos(dt), "\n"));
2281 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2283 switch(self.owner.cvar_cl_gunalign)
2294 if(allowcenter) // 2: allow center handedness
2307 if(allowcenter) // 2: allow center handedness
2323 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2328 if (cvar("g_shootfromeye"))
2332 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2340 else if (cvar("g_shootfromcenter"))
2344 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2352 else if (cvar("g_shootfromclient"))
2354 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2356 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2371 void attach_sameorigin(entity e, entity to, string tag)
2373 vector org, t_forward, t_left, t_up, e_forward, e_up;
2380 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2381 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2382 t_forward = v_forward * tagscale;
2383 t_left = v_right * -tagscale;
2384 t_up = v_up * tagscale;
2386 e.origin_x = org * t_forward;
2387 e.origin_y = org * t_left;
2388 e.origin_z = org * t_up;
2390 // current forward and up directions
2391 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2392 e.angles_x = -e.angles_x;
2393 fixedmakevectors(e.angles);
2395 // untransform forward, up!
2396 e_forward_x = v_forward * t_forward;
2397 e_forward_y = v_forward * t_left;
2398 e_forward_z = v_forward * t_up;
2399 e_up_x = v_up * t_forward;
2400 e_up_y = v_up * t_left;
2401 e_up_z = v_up * t_up;
2403 e.angles = fixedvectoangles2(e_forward, e_up);
2404 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2405 e.angles_x = -e.angles_x;
2407 setattachment(e, to, tag);
2408 setorigin(e, e.origin);
2411 void detach_sameorigin(entity e)
2414 org = gettaginfo(e, 0);
2415 e.angles = fixedvectoangles2(v_forward, v_up);
2416 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2417 e.angles_x = -e.angles_x;
2419 setattachment(e, world, "");
2420 setorigin(e, e.origin);
2423 void follow_sameorigin(entity e, entity to)
2425 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2426 e.aiment = to; // make the hole follow bmodel
2427 e.punchangle = to.angles; // the original angles of bmodel
2428 e.view_ofs = e.origin - to.origin; // relative origin
2429 e.v_angle = e.angles - to.angles; // relative angles
2432 void unfollow_sameorigin(entity e)
2434 e.movetype = MOVETYPE_NONE;
2437 entity gettaginfo_relative_ent;
2438 vector gettaginfo_relative(entity e, float tag)
2440 if (!gettaginfo_relative_ent)
2442 gettaginfo_relative_ent = spawn();
2443 gettaginfo_relative_ent.effects = EF_NODRAW;
2445 gettaginfo_relative_ent.model = e.model;
2446 gettaginfo_relative_ent.modelindex = e.modelindex;
2447 gettaginfo_relative_ent.frame = e.frame;
2448 return gettaginfo(gettaginfo_relative_ent, tag);
2451 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2455 if (pl.soundentity.cnt & p)
2457 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2458 pl.soundentity.cnt |= p;
2461 void SoundEntity_StopSound(entity pl, float chan)
2465 if (pl.soundentity.cnt & p)
2467 stopsoundto(MSG_ALL, pl.soundentity, chan);
2468 pl.soundentity.cnt &~= p;
2472 void SoundEntity_Attach(entity pl)
2474 pl.soundentity = spawn();
2475 pl.soundentity.classname = "soundentity";
2476 pl.soundentity.owner = pl;
2477 setattachment(pl.soundentity, pl, "");
2478 setmodel(pl.soundentity, "null");
2481 void SoundEntity_Detach(entity pl)
2484 for (i = 0; i <= 7; ++i)
2485 SoundEntity_StopSound(pl, i);
2489 float ParseCommandPlayerSlotTarget_firsttoken;
2490 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2498 ParseCommandPlayerSlotTarget_firsttoken = -1;
2502 if (substring(argv(idx), 0, 1) == "#")
2504 s = substring(argv(idx), 1, -1);
2512 ParseCommandPlayerSlotTarget_firsttoken = idx;
2513 if (s == ftos(stof(s)))
2515 e = edict_num(stof(s));
2516 if (e.flags & FL_CLIENT)
2522 // it must be a nick name
2525 ParseCommandPlayerSlotTarget_firsttoken = idx;
2528 FOR_EACH_CLIENT(head)
2529 if (head.netname == s)
2537 s = strdecolorize(s);
2539 FOR_EACH_CLIENT(head)
2540 if (strdecolorize(head.netname) == s)
2555 float modeleffect_SendEntity(entity to, float sf)
2558 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2561 if(self.velocity != '0 0 0')
2563 if(self.angles != '0 0 0')
2565 if(self.avelocity != '0 0 0')
2568 WriteByte(MSG_ENTITY, f);
2569 WriteShort(MSG_ENTITY, self.modelindex);
2570 WriteByte(MSG_ENTITY, self.skin);
2571 WriteByte(MSG_ENTITY, self.frame);
2572 WriteCoord(MSG_ENTITY, self.origin_x);
2573 WriteCoord(MSG_ENTITY, self.origin_y);
2574 WriteCoord(MSG_ENTITY, self.origin_z);
2577 WriteCoord(MSG_ENTITY, self.velocity_x);
2578 WriteCoord(MSG_ENTITY, self.velocity_y);
2579 WriteCoord(MSG_ENTITY, self.velocity_z);
2583 WriteCoord(MSG_ENTITY, self.angles_x);
2584 WriteCoord(MSG_ENTITY, self.angles_y);
2585 WriteCoord(MSG_ENTITY, self.angles_z);
2589 WriteCoord(MSG_ENTITY, self.avelocity_x);
2590 WriteCoord(MSG_ENTITY, self.avelocity_y);
2591 WriteCoord(MSG_ENTITY, self.avelocity_z);
2593 WriteShort(MSG_ENTITY, self.scale * 256.0);
2594 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2595 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2596 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2597 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2602 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)
2607 e.classname = "modeleffect";
2615 e.teleport_time = t1;
2619 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2623 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2626 sz = max(e.scale, e.scale2);
2627 setsize(e, e.mins * sz, e.maxs * sz);
2628 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2631 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2633 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2636 float randombit(float bits)
2638 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2647 for(f = 1; f <= bits; f *= 2)
2656 r = (r - 1) / (n - 1);
2663 float randombits(float bits, float k, float error_return)
2667 while(k > 0 && bits != r)
2669 r += randombit(bits - r);
2678 void randombit_test(float bits, float iter)
2682 print(ftos(randombit(bits)), "\n");
2687 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2689 if(halflifedist > 0)
2690 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2691 else if(halflifedist < 0)
2692 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);