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 string admin_name(void)
12 if(cvar_string("sv_adminnick") != "")
13 return cvar_string("sv_adminnick");
15 return "SERVER ADMIN";
18 float DistributeEvenly_amount;
19 float DistributeEvenly_totalweight;
20 void DistributeEvenly_Init(float amount, float totalweight)
22 if (DistributeEvenly_amount)
24 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
25 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
28 DistributeEvenly_amount = 0;
30 DistributeEvenly_amount = amount;
31 DistributeEvenly_totalweight = totalweight;
33 float DistributeEvenly_Get(float weight)
38 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
39 DistributeEvenly_totalweight -= weight;
40 DistributeEvenly_amount -= f;
44 void move_out_of_solid_expand(entity e, vector by)
47 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
50 if (trace_fraction < 1)
53 // adjust origin in the other direction...
54 setorigin(e,e.origin - by * (1 - trace_fraction));
58 float move_out_of_solid(entity e)
63 traceline(o, o, MOVE_WORLDONLY, e);
67 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
68 if (!trace_startsolid)
75 move_out_of_solid_expand(e, '1 0 0' * m0_x);
77 move_out_of_solid_expand(e, '1 0 0' * m1_x);
79 move_out_of_solid_expand(e, '0 1 0' * m0_y);
81 move_out_of_solid_expand(e, '0 1 0' * m1_y);
83 move_out_of_solid_expand(e, '0 0 1' * m0_z);
85 move_out_of_solid_expand(e, '0 0 1' * m1_z);
87 setorigin(e, e.origin);
89 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
99 string STR_PLAYER = "player";
100 string STR_SPECTATOR = "spectator";
101 string STR_OBSERVER = "observer";
104 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
105 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
106 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
107 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
109 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
110 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
111 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
112 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
113 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
116 // copies a string to a tempstring (so one can strunzone it)
117 string strcat1(string s) = #115; // FRIK_FILE
122 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
124 local float nPlayerHealth = rint(enPlayer.health);
125 local float nPlayerArmor = rint(enPlayer.armorvalue);
126 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
127 local float nPlayerPing = rint(enPlayer.ping);
128 local string strPlayerPingColor;
129 local string strMessage;
130 if(nPlayerPing >= 150)
131 strPlayerPingColor = "^1";
133 strPlayerPingColor = "^2";
135 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
136 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
138 if(cvar("sv_fragmessage_information_ping")) {
139 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
140 strMessage = strcat(strMessage, "\n^7(^2Bot");
142 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
143 if(cvar("sv_fragmessage_information_handicap"))
144 if(cvar("sv_fragmessage_information_handicap") == 2)
145 if(nPlayerHandicap <= 1)
146 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
148 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
149 else if not(nPlayerHandicap <= 1)
150 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
152 strMessage = strcat(strMessage, "^7)");
153 } else if(cvar("sv_fragmessage_information_handicap")) {
154 if(cvar("sv_fragmessage_information_handicap") == 2)
155 if(nPlayerHandicap <= 1)
156 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
158 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
159 else if(nPlayerHandicap > 1)
160 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
164 void bcenterprint(string s)
166 // TODO replace by MSG_ALL (would show it to spectators too, though)?
168 FOR_EACH_PLAYER(head)
169 if (clienttype(head) == CLIENTTYPE_REAL)
170 centerprint(head, s);
173 void GameLogEcho(string s)
178 if (cvar("sv_eventlog_files"))
183 matches = cvar("sv_eventlog_files_counter") + 1;
184 cvar_set("sv_eventlog_files_counter", ftos(matches));
187 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
188 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
189 logfile = fopen(fn, FILE_APPEND);
190 fputs(logfile, ":logversion:3\n");
194 if (cvar("sv_eventlog_files_timestamps"))
195 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
197 fputs(logfile, strcat(s, "\n"));
200 if (cvar("sv_eventlog_console"))
209 // will be opened later
214 if (logfile_open && logfile >= 0)
221 float spawnpoint_nag;
222 void relocate_spawnpoint()
224 // nudge off the floor
225 setorigin(self, self.origin + '0 0 1');
227 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
228 if (trace_startsolid)
234 if (!move_out_of_solid(self))
235 objerror("could not get out of solid at all!");
236 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
237 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
238 print(" ", ftos(self.origin_y - o_y));
239 print(" ", ftos(self.origin_z - o_z), "'\n");
240 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
243 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
249 self.mins = self.maxs = '0 0 0';
250 objerror("player spawn point in solid, mapper sucks!\n");
255 if (cvar("g_spawnpoints_autodrop"))
257 setsize(self, PL_MIN, PL_MAX);
261 self.use = spawnpoint_use;
262 self.team_saved = self.team;
266 if (have_team_spawns != 0)
268 have_team_spawns = 1;
270 if (cvar("r_showbboxes"))
272 // show where spawnpoints point at too
273 makevectors(self.angles);
276 e.classname = "info_player_foo";
277 setorigin(e, self.origin + v_forward * 24);
278 setsize(e, '-8 -8 -8', '8 8 8');
279 e.solid = SOLID_TRIGGER;
283 #define strstr strstrofs
285 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
286 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
287 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
288 // BE CONSTANT OR strzoneD!
289 float strstr(string haystack, string needle, float offset)
293 len = strlen(needle);
294 endpos = strlen(haystack) - len;
295 while(offset <= endpos)
297 found = substring(haystack, offset, len);
306 float NUM_NEAREST_ENTITIES = 4;
307 entity nearest_entity[NUM_NEAREST_ENTITIES];
308 float nearest_length[NUM_NEAREST_ENTITIES];
309 entity findnearest(vector point, .string field, string value, vector axismod)
320 localhead = find(world, field, value);
323 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
324 dist = localhead.oldorigin;
326 dist = localhead.origin;
328 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
331 for (i = 0; i < num_nearest; ++i)
333 if (len < nearest_length[i])
337 // now i tells us where to insert at
338 // INSERTION SORT! YOU'VE SEEN IT! RUN!
339 if (i < NUM_NEAREST_ENTITIES)
341 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
343 nearest_length[j + 1] = nearest_length[j];
344 nearest_entity[j + 1] = nearest_entity[j];
346 nearest_length[i] = len;
347 nearest_entity[i] = localhead;
348 if (num_nearest < NUM_NEAREST_ENTITIES)
349 num_nearest = num_nearest + 1;
352 localhead = find(localhead, field, value);
355 // now use the first one from our list that we can see
356 for (i = 0; i < num_nearest; ++i)
358 traceline(point, nearest_entity[i].origin, TRUE, world);
359 if (trace_fraction == 1)
363 dprint("Nearest point (");
364 dprint(nearest_entity[0].netname);
365 dprint(") is not visible, using a visible one.\n");
367 return nearest_entity[i];
371 if (num_nearest == 0)
374 dprint("Not seeing any location point, using nearest as fallback.\n");
376 dprint("Candidates were: ");
377 for(j = 0; j < num_nearest; ++j)
381 dprint(nearest_entity[j].netname);
386 return nearest_entity[0];
389 void spawnfunc_target_location()
391 self.classname = "target_location";
392 // location name in netname
393 // eventually support: count, teamgame selectors, line of sight?
396 void spawnfunc_info_location()
398 self.classname = "target_location";
399 self.message = self.netname;
402 string NearestLocation(vector p)
407 loc = findnearest(p, classname, "target_location", '1 1 1');
414 loc = findnearest(p, target, "###item###", '1 1 4');
421 string formatmessage(string msg)
432 break; // too many replacements
434 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
435 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
445 replacement = substring(msg, p, 2);
446 escape = substring(msg, p + 1, 1);
449 else if (escape == "\\")
451 else if (escape == "n")
453 else if (escape == "a")
454 replacement = ftos(floor(self.armorvalue));
455 else if (escape == "h")
456 replacement = ftos(floor(self.health));
457 else if (escape == "l")
458 replacement = NearestLocation(self.origin);
459 else if (escape == "y")
460 replacement = NearestLocation(self.cursor_trace_endpos);
461 else if (escape == "d")
462 replacement = NearestLocation(self.death_origin);
463 else if (escape == "w")
468 wep = self.switchweapon;
471 replacement = W_Name(wep);
473 else if (escape == "W")
475 if (self.items & IT_SHELLS) replacement = "shells";
476 else if (self.items & IT_NAILS) replacement = "bullets";
477 else if (self.items & IT_ROCKETS) replacement = "rockets";
478 else if (self.items & IT_CELLS) replacement = "cells";
479 else replacement = "batteries"; // ;)
481 else if (escape == "x")
483 replacement = self.cursor_trace_ent.netname;
484 if (!replacement || !self.cursor_trace_ent)
485 replacement = "nothing";
487 else if (escape == "p")
489 if (self.last_selected_player)
490 replacement = self.last_selected_player.netname;
492 replacement = "(nobody)";
494 else if (escape == "s")
495 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
496 else if (escape == "S")
497 replacement = ftos(vlen(self.velocity));
498 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
499 p = p + strlen(replacement);
510 >0: receives a cvar from name=argv(f) value=argv(f+1)
512 void GetCvars_handleString(string thisname, float f, .string field, string name)
517 strunzone(self.field);
518 self.field = string_null;
522 if (thisname == name)
525 strunzone(self.field);
526 self.field = strzone(argv(f + 1));
530 stuffcmd(self, strcat("sendcvar ", name, "\n"));
532 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
534 GetCvars_handleString(thisname, f, field, name);
535 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
536 if (thisname == name)
539 s = func(strcat1(self.field));
542 strunzone(self.field);
543 self.field = strzone(s);
547 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
554 if (thisname == name)
555 self.field = stof(argv(f + 1));
558 stuffcmd(self, strcat("sendcvar ", name, "\n"));
560 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
567 if (thisname == name)
571 self.field = stof(argv(f + 1));
580 stuffcmd(self, strcat("sendcvar ", name, "\n"));
583 string W_FixWeaponOrder_ForceComplete(string s);
584 string W_FixWeaponOrder_AllowIncomplete(string s);
585 float w_getbestweapon(entity e);
586 void GetCvars(float f)
590 s = strcat1(argv(f));
591 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
592 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
593 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
594 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
595 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
596 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
597 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
598 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
599 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
600 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
601 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
602 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
603 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
604 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
605 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
606 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
607 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
608 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
609 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
610 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
611 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
612 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
613 #ifdef ALLOW_FORCEMODELS
614 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
615 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
617 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
620 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
623 if (s == "cl_weaponpriority")
624 self.switchweapon = w_getbestweapon(self);
628 float fexists(string f)
631 fh = fopen(f, FILE_READ);
638 void backtrace(string msg)
641 dev = cvar("developer");
642 war = cvar("prvm_backtraceforwarnings");
643 cvar_set("developer", "1");
644 cvar_set("prvm_backtraceforwarnings", "1");
646 dprint("--- CUT HERE ---\nWARNING: ");
649 remove(world); // isn't there any better way to cause a backtrace?
650 dprint("\n--- CUT UNTIL HERE ---\n");
651 cvar_set("developer", ftos(dev));
652 cvar_set("prvm_backtraceforwarnings", ftos(war));
655 string Team_ColorCode(float teamid)
657 if (teamid == COLOR_TEAM1)
659 else if (teamid == COLOR_TEAM2)
661 else if (teamid == COLOR_TEAM3)
663 else if (teamid == COLOR_TEAM4)
669 string Team_ColorName(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 string Team_ColorNameLowerCase(float t)
685 // fixme: Search for team entities and get their .netname's!
686 if (t == COLOR_TEAM1)
688 if (t == COLOR_TEAM2)
690 if (t == COLOR_TEAM3)
692 if (t == COLOR_TEAM4)
697 #define CENTERPRIO_POINT 1
698 #define CENTERPRIO_SPAM 2
699 #define CENTERPRIO_VOTE 4
700 #define CENTERPRIO_NORMAL 5
701 #define CENTERPRIO_SHIELDING 7
702 #define CENTERPRIO_MAPVOTE 9
703 #define CENTERPRIO_IDLEKICK 50
704 #define CENTERPRIO_ADMIN 99
705 .float centerprint_priority;
706 .float centerprint_expires;
707 void centerprint_atprio(entity e, float prio, string s)
709 if (intermission_running)
710 if (prio < CENTERPRIO_MAPVOTE)
712 if (time > e.centerprint_expires)
713 e.centerprint_priority = 0;
714 if (prio >= e.centerprint_priority)
716 e.centerprint_priority = prio;
717 if (timeoutStatus == 2)
718 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
720 e.centerprint_expires = time + e.cvar_scr_centertime;
721 centerprint_builtin(e, s);
724 void centerprint_expire(entity e, float prio)
726 if (prio == e.centerprint_priority)
728 e.centerprint_priority = 0;
729 centerprint_builtin(e, "");
732 void centerprint(entity e, string s)
734 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
737 // decolorizes and team colors the player name when needed
738 string playername(entity p)
741 if (teams_matter && !intermission_running && p.classname == "player")
743 t = Team_ColorCode(p.team);
744 return strcat(t, strdecolorize(p.netname));
750 vector randompos(vector m1, vector m2)
754 v_x = m2_x * random() + m1_x;
755 v_y = m2_y * random() + m1_y;
756 v_z = m2_z * random() + m1_z;
760 float g_pickup_shells;
761 float g_pickup_shells_max;
762 float g_pickup_nails;
763 float g_pickup_nails_max;
764 float g_pickup_rockets;
765 float g_pickup_rockets_max;
766 float g_pickup_cells;
767 float g_pickup_cells_max;
769 float g_pickup_fuel_jetpack;
770 float g_pickup_fuel_max;
771 float g_pickup_armorsmall;
772 float g_pickup_armorsmall_max;
773 float g_pickup_armormedium;
774 float g_pickup_armormedium_max;
775 float g_pickup_armorbig;
776 float g_pickup_armorbig_max;
777 float g_pickup_armorlarge;
778 float g_pickup_armorlarge_max;
779 float g_pickup_healthsmall;
780 float g_pickup_healthsmall_max;
781 float g_pickup_healthmedium;
782 float g_pickup_healthmedium_max;
783 float g_pickup_healthlarge;
784 float g_pickup_healthlarge_max;
785 float g_pickup_healthmega;
786 float g_pickup_healthmega_max;
788 float g_weaponarena_random;
789 string g_weaponarena_list;
790 float g_weaponspeedfactor;
791 float g_weaponratefactor;
792 float g_weapondamagefactor;
793 float g_weaponforcefactor;
797 float start_ammo_shells;
798 float start_ammo_nails;
799 float start_ammo_rockets;
800 float start_ammo_cells;
801 float start_ammo_fuel;
803 float start_armorvalue;
804 float warmup_start_weapons;
805 float warmup_start_ammo_shells;
806 float warmup_start_ammo_nails;
807 float warmup_start_ammo_rockets;
808 float warmup_start_ammo_cells;
809 float warmup_start_ammo_fuel;
810 float warmup_start_health;
811 float warmup_start_armorvalue;
815 entity get_weaponinfo(float w);
817 float NixNex_CanChooseWeapon(float wpn);
818 void readplayerstartcvars()
824 // initialize starting values for players
827 start_ammo_shells = 0;
828 start_ammo_nails = 0;
829 start_ammo_rockets = 0;
830 start_ammo_cells = 0;
831 start_health = cvar("g_balance_health_start");
832 start_armorvalue = cvar("g_balance_armor_start");
835 s = cvar_string("g_weaponarena");
841 g_weaponarena_list = "All Weapons";
842 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
844 e = get_weaponinfo(j);
845 g_weaponarena |= e.weapons;
846 weapon_action(e.weapon, WR_PRECACHE);
849 else if (s == "most")
851 g_weaponarena_list = "Most Weapons";
852 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
854 e = get_weaponinfo(j);
855 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
857 g_weaponarena |= e.weapons;
858 weapon_action(e.weapon, WR_PRECACHE);
862 else if (s == "none")
864 g_weaponarena_list = "No Weapons";
865 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
869 t = tokenize_console(s);
870 g_weaponarena_list = "";
871 for (i = 0; i < t; ++i)
874 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
876 e = get_weaponinfo(j);
879 g_weaponarena |= e.weapons;
880 weapon_action(e.weapon, WR_PRECACHE);
881 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
887 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
890 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
894 g_weaponarena_random = cvar("g_weaponarena_random");
896 g_weaponarena_random = 0;
901 // will be done later
902 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
903 if (NixNex_CanChooseWeapon(i))
904 weapon_action(i, WR_PRECACHE);
905 if(!cvar("g_use_ammunition"))
906 start_items |= IT_UNLIMITED_AMMO;
908 else if (g_weaponarena)
910 start_weapons = g_weaponarena;
911 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
912 start_ammo_rockets = 999;
913 if (g_weaponarena & WEPBIT_SHOTGUN)
914 start_ammo_shells = 999;
915 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
916 start_ammo_cells = 999;
917 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
918 start_ammo_nails = 999;
919 if (g_weaponarena & WEPBIT_HOOK)
920 start_ammo_fuel = 999;
921 start_items |= IT_UNLIMITED_AMMO;
923 else if (g_minstagib)
926 start_armorvalue = 0;
927 start_weapons = WEPBIT_MINSTANEX;
928 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
929 start_ammo_cells = cvar("g_minstagib_ammo_start");
930 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
931 start_ammo_fuel = cvar("g_start_ammo_fuel");
933 if (g_minstagib_invis_alpha <= 0)
934 g_minstagib_invis_alpha = -1;
940 start_ammo_shells = cvar("g_lms_start_ammo_shells");
941 start_ammo_nails = cvar("g_lms_start_ammo_nails");
942 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
943 start_ammo_cells = cvar("g_lms_start_ammo_cells");
944 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
945 start_health = cvar("g_lms_start_health");
946 start_armorvalue = cvar("g_lms_start_armor");
948 else if (cvar("g_use_ammunition"))
950 start_ammo_shells = cvar("g_start_ammo_shells");
951 start_ammo_nails = cvar("g_start_ammo_nails");
952 start_ammo_rockets = cvar("g_start_ammo_rockets");
953 start_ammo_cells = cvar("g_start_ammo_cells");
954 start_ammo_fuel = cvar("g_start_ammo_fuel");
958 start_ammo_shells = cvar("g_pickup_shells_max");
959 start_ammo_nails = cvar("g_pickup_nails_max");
960 start_ammo_rockets = cvar("g_pickup_rockets_max");
961 start_ammo_cells = cvar("g_pickup_cells_max");
962 start_ammo_fuel = cvar("g_pickup_fuel_max");
963 start_items |= IT_UNLIMITED_AMMO;
966 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
968 e = get_weaponinfo(i);
972 t = cvar(strcat("g_start_weapon_", e.netname));
974 if (t < 0) // "default" weapon selection
977 t = (e.spawnflags & WEPSPAWNFLAG_NORMAL);
978 else if (g_race || g_cts)
979 t = (i == WEP_LASER);
981 t = 0; // weapon is set a few lines later
983 t = (i == WEP_LASER || i == WEP_SHOTGUN);
984 if (g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
985 t += (i == WEP_HOOK);
988 if (g_nexball && i == WEP_PORTO)
993 start_weapons |= e.weapons;
994 weapon_action(e.weapon, WR_PRECACHE);
1001 warmup_start_ammo_shells = start_ammo_shells;
1002 warmup_start_ammo_nails = start_ammo_nails;
1003 warmup_start_ammo_rockets = start_ammo_rockets;
1004 warmup_start_ammo_cells = start_ammo_cells;
1005 warmup_start_ammo_fuel = start_ammo_fuel;
1006 warmup_start_health = start_health;
1007 warmup_start_armorvalue = start_armorvalue;
1008 warmup_start_weapons = start_weapons;
1010 if (!g_weaponarena && !g_nixnex && !g_minstagib)
1012 if (cvar("g_use_ammunition"))
1014 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
1015 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
1016 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
1017 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
1018 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
1020 warmup_start_health = cvar("g_warmup_start_health");
1021 warmup_start_armorvalue = cvar("g_warmup_start_armor");
1022 if (cvar("g_warmup_allguns"))
1024 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
1026 e = get_weaponinfo(i);
1029 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
1031 warmup_start_weapons |= e.weapons;
1032 weapon_action(e.weapon, WR_PRECACHE);
1039 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
1041 g_grappling_hook = 0; // these two can't coexist, as they use the same button
1042 start_items |= IT_FUEL_REGEN;
1043 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1044 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
1048 start_items |= IT_JETPACK;
1050 if (g_weapon_stay == 2)
1052 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
1053 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
1054 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
1055 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
1056 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
1057 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
1058 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
1059 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
1060 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
1061 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
1064 start_ammo_shells = max(0, start_ammo_shells);
1065 start_ammo_nails = max(0, start_ammo_nails);
1066 start_ammo_cells = max(0, start_ammo_cells);
1067 start_ammo_rockets = max(0, start_ammo_rockets);
1068 start_ammo_fuel = max(0, start_ammo_fuel);
1070 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1071 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1072 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1073 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1074 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1078 float g_bugrigs_planar_movement;
1079 float g_bugrigs_planar_movement_car_jumping;
1080 float g_bugrigs_reverse_spinning;
1081 float g_bugrigs_reverse_speeding;
1082 float g_bugrigs_reverse_stopping;
1083 float g_bugrigs_air_steering;
1084 float g_bugrigs_angle_smoothing;
1085 float g_bugrigs_friction_floor;
1086 float g_bugrigs_friction_brake;
1087 float g_bugrigs_friction_air;
1088 float g_bugrigs_accel;
1089 float g_bugrigs_speed_ref;
1090 float g_bugrigs_speed_pow;
1091 float g_bugrigs_steer;
1093 float g_touchexplode;
1094 float g_touchexplode_radius;
1095 float g_touchexplode_damage;
1096 float g_touchexplode_edgedamage;
1097 float g_touchexplode_force;
1104 float sv_pitch_fixyaw;
1106 void readlevelcvars(void)
1108 g_bugrigs = cvar("g_bugrigs");
1109 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1110 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1111 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1112 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1113 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1114 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1115 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1116 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1117 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1118 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1119 g_bugrigs_accel = cvar("g_bugrigs_accel");
1120 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1121 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1122 g_bugrigs_steer = cvar("g_bugrigs_steer");
1124 g_touchexplode = cvar("g_touchexplode");
1125 g_touchexplode_radius = cvar("g_touchexplode_radius");
1126 g_touchexplode_damage = cvar("g_touchexplode_damage");
1127 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1128 g_touchexplode_force = cvar("g_touchexplode_force");
1130 #ifdef ALLOW_FORCEMODELS
1131 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1133 sv_loddistance1 = cvar("sv_loddistance1");
1134 sv_loddistance2 = cvar("sv_loddistance2");
1135 if(sv_loddistance2 <= sv_loddistance1)
1136 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1137 sv_clones = cvar("sv_clones");
1138 sv_cheats = cvar("sv_cheats");
1139 sv_gentle = cvar("sv_gentle");
1140 sv_foginterval = cvar("sv_foginterval");
1141 g_cloaked = cvar("g_cloaked");
1142 g_jump_grunt = cvar("g_jump_grunt");
1143 g_footsteps = cvar("g_footsteps");
1144 g_grappling_hook = cvar("g_grappling_hook");
1145 g_jetpack = cvar("g_jetpack");
1146 g_laserguided_missile = cvar("g_laserguided_missile");
1147 g_midair = cvar("g_midair");
1148 g_minstagib = cvar("g_minstagib");
1149 g_nixnex = cvar("g_nixnex");
1150 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1151 g_norecoil = cvar("g_norecoil");
1152 g_vampire = cvar("g_vampire");
1153 g_bloodloss = cvar("g_bloodloss");
1154 sv_maxidle = cvar("sv_maxidle");
1155 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1156 sv_pogostick = cvar("sv_pogostick");
1157 sv_doublejump = cvar("sv_doublejump");
1158 g_ctf_reverse = cvar("g_ctf_reverse");
1159 sv_autotaunt = cvar("sv_autotaunt");
1160 sv_taunt = cvar("sv_taunt");
1162 inWarmupStage = cvar("g_warmup");
1163 g_warmup_limit = cvar("g_warmup_limit");
1164 g_warmup_allguns = cvar("g_warmup_allguns");
1165 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1167 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1168 inWarmupStage = 0; // these modes cannot work together, sorry
1170 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1171 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1172 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1173 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1174 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1175 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1176 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1177 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1178 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1179 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1180 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1181 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1183 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1184 if (g_nixnex) g_weaponarena = 0;
1187 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1188 g_weaponratefactor = cvar("g_weaponratefactor");
1189 g_weapondamagefactor = cvar("g_weapondamagefactor");
1190 g_weaponforcefactor = cvar("g_weaponforcefactor");
1192 g_pickup_shells = cvar("g_pickup_shells");
1193 g_pickup_shells_max = cvar("g_pickup_shells_max");
1194 g_pickup_nails = cvar("g_pickup_nails");
1195 g_pickup_nails_max = cvar("g_pickup_nails_max");
1196 g_pickup_rockets = cvar("g_pickup_rockets");
1197 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1198 g_pickup_cells = cvar("g_pickup_cells");
1199 g_pickup_cells_max = cvar("g_pickup_cells_max");
1200 g_pickup_fuel = cvar("g_pickup_fuel");
1201 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1202 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1203 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1204 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1205 g_pickup_armormedium = cvar("g_pickup_armormedium");
1206 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1207 g_pickup_armorbig = cvar("g_pickup_armorbig");
1208 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1209 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1210 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1211 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1212 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1213 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1214 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1215 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1216 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1217 g_pickup_healthmega = cvar("g_pickup_healthmega");
1218 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1220 g_pinata = cvar("g_pinata");
1222 g_weapon_stay = cvar("g_weapon_stay");
1223 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1225 g_ghost_items = cvar("g_ghost_items");
1226 if(g_ghost_items >= 1)
1227 g_ghost_items = 0.13; // default alpha value
1229 if not(inWarmupStage)
1230 game_starttime = cvar("g_start_delay");
1232 sv_pitch_min = cvar("sv_pitch_min");
1233 sv_pitch_max = cvar("sv_pitch_max");
1234 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1236 readplayerstartcvars();
1240 // TODO sound pack system
1243 string precache_sound_builtin (string s) = #19;
1244 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1245 string precache_sound(string s)
1247 return precache_sound_builtin(strcat(soundpack, s));
1249 void play2(entity e, string filename)
1251 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1253 void sound(entity e, float chan, string samp, float vol, float atten)
1255 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1260 string precache_sound (string s) = #19;
1261 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1262 float precache_sound_index (string s) = #19;
1264 #define SND_VOLUME 1
1265 #define SND_ATTENUATION 2
1266 #define SND_LARGEENTITY 8
1267 #define SND_LARGESOUND 16
1269 float sound_allowed(float dest, entity e)
1271 // sounds from world may always pass
1274 if (e.classname == "body")
1276 if (e.owner && e.owner != e)
1281 // sounds to self may always pass
1282 if (dest == MSG_ONE)
1283 if (e == msg_entity)
1285 // sounds by players can be removed
1286 if (cvar("bot_sound_monopoly"))
1287 if (clienttype(e) == CLIENTTYPE_REAL)
1289 // anything else may pass
1293 void sound(entity e, float chan, string samp, float vol, float atten)
1295 if (!sound_allowed(MSG_BROADCAST, e))
1297 sound_builtin(e, chan, samp, vol, atten);
1299 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1303 if (!sound_allowed(dest, e))
1306 entno = num_for_edict(e);
1307 idx = precache_sound_index(samp);
1312 atten = floor(atten * 64);
1313 vol = floor(vol * 255);
1316 sflags |= SND_VOLUME;
1318 sflags |= SND_ATTENUATION;
1320 sflags |= SND_LARGEENTITY;
1322 sflags |= SND_LARGESOUND;
1324 WriteByte(dest, SVC_SOUND);
1325 WriteByte(dest, sflags);
1326 if (sflags & SND_VOLUME)
1327 WriteByte(dest, vol);
1328 if (sflags & SND_ATTENUATION)
1329 WriteByte(dest, atten);
1330 if (sflags & SND_LARGEENTITY)
1332 WriteShort(dest, entno);
1333 WriteByte(dest, chan);
1337 WriteShort(dest, entno * 8 + chan);
1339 if (sflags & SND_LARGESOUND)
1340 WriteShort(dest, idx);
1342 WriteByte(dest, idx);
1344 WriteCoord(dest, o_x);
1345 WriteCoord(dest, o_y);
1346 WriteCoord(dest, o_z);
1348 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1352 if (!sound_allowed(dest, e))
1355 o = e.origin + 0.5 * (e.mins + e.maxs);
1356 soundtoat(dest, e, o, chan, samp, vol, atten);
1358 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1360 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1362 void stopsoundto(float dest, entity e, float chan)
1366 if (!sound_allowed(dest, e))
1369 entno = num_for_edict(e);
1374 idx = precache_sound_index("misc/null.wav");
1375 sflags = SND_LARGEENTITY;
1377 sflags |= SND_LARGESOUND;
1378 WriteByte(dest, SVC_SOUND);
1379 WriteByte(dest, sflags);
1380 WriteShort(dest, entno);
1381 WriteByte(dest, chan);
1382 if (sflags & SND_LARGESOUND)
1383 WriteShort(dest, idx);
1385 WriteByte(dest, idx);
1386 WriteCoord(dest, e.origin_x);
1387 WriteCoord(dest, e.origin_y);
1388 WriteCoord(dest, e.origin_z);
1392 WriteByte(dest, SVC_STOPSOUND);
1393 WriteShort(dest, entno * 8 + chan);
1396 void stopsound(entity e, float chan)
1398 if (!sound_allowed(MSG_BROADCAST, e))
1401 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1402 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1405 void play2(entity e, string filename)
1407 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1409 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1412 .float announcetime;
1413 float announce(entity player, string msg)
1415 if (time > player.announcetime)
1416 if (clienttype(player) == CLIENTTYPE_REAL)
1418 player.announcetime = time + 0.8;
1424 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1425 float spamsound(entity e, float chan, string samp, float vol, float atten)
1427 if (!sound_allowed(MSG_BROADCAST, e))
1430 if (time > e.announcetime)
1432 e.announcetime = time;
1433 sound(e, chan, samp, vol, atten);
1439 void play2team(float t, string filename)
1443 if (cvar("bot_sound_monopoly"))
1446 FOR_EACH_REALPLAYER(head)
1449 play2(head, filename);
1453 void play2all(string samp)
1455 if (cvar("bot_sound_monopoly"))
1458 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1461 void PrecachePlayerSounds(string f);
1462 void precache_all_models(string pattern)
1464 float globhandle, i, n;
1467 globhandle = search_begin(pattern, TRUE, FALSE);
1470 n = search_getsize(globhandle);
1471 for (i = 0; i < n; ++i)
1473 //print(search_getfilename(globhandle, i), "\n");
1474 f = search_getfilename(globhandle, i);
1477 if(substring(f, -9,5) == "_lod1")
1479 if(substring(f, -9,5) == "_lod2")
1481 if(!sv_loddistance1)
1483 PrecachePlayerSounds(strcat(f, ".sounds"));
1485 search_end(globhandle);
1490 // gamemode related things
1491 precache_model ("models/misc/chatbubble.spr");
1492 precache_model ("models/misc/teambubble.spr");
1495 precache_model ("models/runematch/curse.mdl");
1496 precache_model ("models/runematch/rune.mdl");
1499 #ifdef TTURRETS_ENABLED
1500 if (cvar("g_turrets"))
1504 // Precache all player models if desired
1505 if (cvar("sv_precacheplayermodels"))
1507 PrecachePlayerSounds("sound/player/default.sounds");
1508 precache_all_models("models/player/*.zym");
1509 precache_all_models("models/player/*.dpm");
1510 precache_all_models("models/player/*.md3");
1511 precache_all_models("models/player/*.psk");
1512 //precache_model("models/player/carni.zym");
1513 //precache_model("models/player/crash.zym");
1514 //precache_model("models/player/grunt.zym");
1515 //precache_model("models/player/headhunter.zym");
1516 //precache_model("models/player/insurrectionist.zym");
1517 //precache_model("models/player/jeandarc.zym");
1518 //precache_model("models/player/lurk.zym");
1519 //precache_model("models/player/lycanthrope.zym");
1520 //precache_model("models/player/marine.zym");
1521 //precache_model("models/player/nexus.zym");
1522 //precache_model("models/player/pyria.zym");
1523 //precache_model("models/player/shock.zym");
1524 //precache_model("models/player/skadi.zym");
1525 //precache_model("models/player/specop.zym");
1526 //precache_model("models/player/visitant.zym");
1529 if (cvar("sv_defaultcharacter"))
1532 s = cvar_string("sv_defaultplayermodel_red");
1536 PrecachePlayerSounds(strcat(s, ".sounds"));
1538 s = cvar_string("sv_defaultplayermodel_blue");
1542 PrecachePlayerSounds(strcat(s, ".sounds"));
1544 s = cvar_string("sv_defaultplayermodel_yellow");
1548 PrecachePlayerSounds(strcat(s, ".sounds"));
1550 s = cvar_string("sv_defaultplayermodel_pink");
1554 PrecachePlayerSounds(strcat(s, ".sounds"));
1556 s = cvar_string("sv_defaultplayermodel");
1560 PrecachePlayerSounds(strcat(s, ".sounds"));
1566 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1567 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1570 // gore and miscellaneous sounds
1571 //precache_sound ("misc/h2ohit.wav");
1572 precache_model ("models/hook.md3");
1573 precache_sound ("misc/armorimpact.wav");
1574 precache_sound ("misc/bodyimpact1.wav");
1575 precache_sound ("misc/bodyimpact2.wav");
1576 precache_sound ("misc/gib.wav");
1577 precache_sound ("misc/gib_splat01.wav");
1578 precache_sound ("misc/gib_splat02.wav");
1579 precache_sound ("misc/gib_splat03.wav");
1580 precache_sound ("misc/gib_splat04.wav");
1581 precache_sound ("misc/hit.wav");
1582 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1583 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1584 precache_sound ("misc/null.wav");
1585 precache_sound ("misc/spawn.wav");
1586 precache_sound ("misc/talk.wav");
1587 precache_sound ("misc/teleport.wav");
1588 precache_sound ("misc/poweroff.wav");
1589 precache_sound ("player/lava.wav");
1590 precache_sound ("player/slime.wav");
1593 precache_sound ("misc/jetpack_fly.wav");
1595 // announcer sounds - male
1596 precache_sound ("announcer/male/electrobitch.wav");
1597 precache_sound ("announcer/male/airshot.wav");
1598 precache_sound ("announcer/male/03kills.wav");
1599 precache_sound ("announcer/male/05kills.wav");
1600 precache_sound ("announcer/male/10kills.wav");
1601 precache_sound ("announcer/male/15kills.wav");
1602 precache_sound ("announcer/male/20kills.wav");
1603 precache_sound ("announcer/male/25kills.wav");
1604 precache_sound ("announcer/male/30kills.wav");
1605 precache_sound ("announcer/male/botlike.wav");
1606 precache_sound ("announcer/male/yoda.wav");
1607 precache_sound ("announcer/male/amazing.wav");
1608 precache_sound ("announcer/male/awesome.wav");
1609 precache_sound ("announcer/male/headshot.wav");
1610 precache_sound ("announcer/male/impressive.wav");
1612 // announcer sounds - robotic
1613 precache_sound ("announcer/robotic/prepareforbattle.wav");
1614 precache_sound ("announcer/robotic/begin.wav");
1615 precache_sound ("announcer/robotic/timeoutcalled.wav");
1616 precache_sound ("announcer/robotic/1fragleft.wav");
1617 precache_sound ("announcer/robotic/2fragsleft.wav");
1618 precache_sound ("announcer/robotic/3fragsleft.wav");
1619 precache_sound ("announcer/robotic/terminated.wav");
1622 precache_sound ("announcer/robotic/lastsecond.wav");
1623 precache_sound ("announcer/robotic/narrowly.wav");
1626 precache_model ("models/sprites/0.spr32");
1627 precache_model ("models/sprites/1.spr32");
1628 precache_model ("models/sprites/2.spr32");
1629 precache_model ("models/sprites/3.spr32");
1630 precache_model ("models/sprites/4.spr32");
1631 precache_model ("models/sprites/5.spr32");
1632 precache_model ("models/sprites/6.spr32");
1633 precache_model ("models/sprites/7.spr32");
1634 precache_model ("models/sprites/8.spr32");
1635 precache_model ("models/sprites/9.spr32");
1636 precache_model ("models/sprites/10.spr32");
1637 precache_sound ("announcer/robotic/1.wav");
1638 precache_sound ("announcer/robotic/2.wav");
1639 precache_sound ("announcer/robotic/3.wav");
1640 precache_sound ("announcer/robotic/4.wav");
1641 precache_sound ("announcer/robotic/5.wav");
1642 precache_sound ("announcer/robotic/6.wav");
1643 precache_sound ("announcer/robotic/7.wav");
1644 precache_sound ("announcer/robotic/8.wav");
1645 precache_sound ("announcer/robotic/9.wav");
1646 precache_sound ("announcer/robotic/10.wav");
1648 // common weapon precaches
1649 precache_sound ("weapons/weapon_switch.wav");
1650 precache_sound ("weapons/weaponpickup.wav");
1651 precache_sound ("weapons/unavailable.wav");
1652 if (g_grappling_hook)
1654 precache_sound ("weapons/hook_fire.wav"); // hook
1655 precache_sound ("weapons/hook_impact.wav"); // hook
1658 if (cvar("sv_precacheweapons") || g_nixnex)
1660 //precache weapon models/sounds
1663 while (wep <= WEP_LAST)
1665 weapon_action(wep, WR_PRECACHE);
1670 precache_model("models/elaser.mdl");
1671 precache_model("models/laser.mdl");
1672 precache_model("models/ebomb.mdl");
1675 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1677 if (!self.noise && self.music) // quake 3 uses the music field
1678 self.noise = self.music;
1680 // plays music for the level if there is any
1683 precache_sound (self.noise);
1684 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1689 // sorry, but using \ in macros breaks line numbers
1690 #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
1691 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1692 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1694 vector ExactTriggerHit_mins;
1695 vector ExactTriggerHit_maxs;
1696 float ExactTriggerHit_Recurse()
1702 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1705 if (trace_ent == self)
1710 se.solid = SOLID_NOT;
1711 f = ExactTriggerHit_Recurse();
1717 float ExactTriggerHit()
1721 if not(self.modelindex)
1725 self.solid = SOLID_BSP;
1726 ExactTriggerHit_mins = other.absmin;
1727 ExactTriggerHit_maxs = other.absmax;
1728 f = ExactTriggerHit_Recurse();
1734 // WARNING: this kills the trace globals
1735 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1736 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1738 #define INITPRIO_FIRST 0
1739 #define INITPRIO_GAMETYPE 0
1740 #define INITPRIO_GAMETYPE_FALLBACK 1
1741 #define INITPRIO_CVARS 5
1742 #define INITPRIO_FINDTARGET 10
1743 #define INITPRIO_DROPTOFLOOR 20
1744 #define INITPRIO_SETLOCATION 90
1745 #define INITPRIO_LINKDOORS 91
1746 #define INITPRIO_LAST 99
1748 .void(void) initialize_entity;
1749 .float initialize_entity_order;
1750 .entity initialize_entity_next;
1751 entity initialize_entity_first;
1753 void make_safe_for_remove(entity e)
1755 if (e.initialize_entity)
1758 for (ent = initialize_entity_first; ent; )
1760 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1762 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1763 // skip it in linked list
1766 prev.initialize_entity_next = ent.initialize_entity_next;
1767 ent = prev.initialize_entity_next;
1771 initialize_entity_first = ent.initialize_entity_next;
1772 ent = initialize_entity_first;
1778 ent = ent.initialize_entity_next;
1784 void objerror(string s)
1786 make_safe_for_remove(self);
1787 objerror_builtin(s);
1790 void remove_unsafely(entity e)
1795 void remove_safely(entity e)
1797 make_safe_for_remove(e);
1801 void InitializeEntity(entity e, void(void) func, float order)
1805 if (!e || e.initialize_entity)
1807 // make a proxy initializer entity
1811 e.classname = "initialize_entity";
1815 e.initialize_entity = func;
1816 e.initialize_entity_order = order;
1818 cur = initialize_entity_first;
1821 if (!cur || cur.initialize_entity_order > order)
1823 // insert between prev and cur
1825 prev.initialize_entity_next = e;
1827 initialize_entity_first = e;
1828 e.initialize_entity_next = cur;
1832 cur = cur.initialize_entity_next;
1835 void InitializeEntitiesRun()
1838 startoflist = initialize_entity_first;
1839 initialize_entity_first = world;
1840 for (self = startoflist; self; )
1843 var void(void) func;
1844 e = self.initialize_entity_next;
1845 func = self.initialize_entity;
1846 self.initialize_entity_order = 0;
1847 self.initialize_entity = func_null;
1848 self.initialize_entity_next = world;
1849 if (self.classname == "initialize_entity")
1853 remove_builtin(self);
1856 //dprint("Delayed initialization: ", self.classname, "\n");
1862 .float uncustomizeentityforclient_set;
1863 .void(void) uncustomizeentityforclient;
1864 void(void) SUB_Nullpointer = #0;
1865 void UncustomizeEntitiesRun()
1869 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1870 self.uncustomizeentityforclient();
1873 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1875 e.customizeentityforclient = customizer;
1876 e.uncustomizeentityforclient = uncustomizer;
1877 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1881 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1884 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1888 if (e.classname == "")
1889 e.classname = "net_linked";
1891 if (e.model == "" || self.modelindex == 0)
1895 setmodel(e, "null");
1899 e.SendEntity = sendfunc;
1900 e.SendFlags = 0xFFFFFF;
1903 e.effects |= EF_NODEPTHTEST;
1907 e.nextthink = time + dt;
1908 e.think = SUB_Remove;
1912 void adaptor_think2touch()
1921 void adaptor_think2use()
1933 // deferred dropping
1934 void DropToFloor_Handler()
1936 droptofloor_builtin();
1937 self.dropped_origin = self.origin;
1942 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1947 float trace_hits_box_a0, trace_hits_box_a1;
1949 float trace_hits_box_1d(float end, float thmi, float thma)
1953 // just check if x is in range
1961 // do the trace with respect to x
1962 // 0 -> end has to stay in thmi -> thma
1963 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1964 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1965 if (trace_hits_box_a0 > trace_hits_box_a1)
1971 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1976 // now it is a trace from 0 to end
1978 trace_hits_box_a0 = 0;
1979 trace_hits_box_a1 = 1;
1981 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1983 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1985 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1991 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1993 return trace_hits_box(start, end, thmi - ma, thma - mi);
1996 float SUB_NoImpactCheck()
1998 // zero hitcontents = this is not the real impact, but either the
1999 // mirror-impact of something hitting the projectile instead of the
2000 // projectile hitting the something, or a touchareagrid one. Neither of
2001 // these stop the projectile from moving, so...
2002 if(trace_dphitcontents == 0)
2004 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
2007 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2009 if (other == world && self.size != '0 0 0')
2012 tic = self.velocity * sys_ticrate;
2013 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
2014 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
2015 if (trace_fraction >= 1)
2017 dprint("Odd... did not hit...?\n");
2019 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
2021 dprint("Detected and prevented the sky-grapple bug.\n");
2029 #define SUB_OwnerCheck() (other && (other == self.owner))
2031 #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)
2033 float MAX_IPBAN_URIS = 16;
2035 float URI_GET_DISCARD = 0;
2036 float URI_GET_IPBAN = 1;
2037 float URI_GET_IPBAN_END = 16;
2039 void URI_Get_Callback(float id, float status, string data)
2041 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
2043 dprint("\nEnd of data.\n");
2045 if (id == URI_GET_DISCARD)
2049 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
2052 OnlineBanList_URI_Get_Callback(id, status, data);
2056 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
2060 void print_to(entity e, string s)
2063 sprint(e, strcat(s, "\n"));
2082 for (i = 0; i < MapInfo_count; ++i)
2084 if (MapInfo_Get_ByID(i))
2086 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2089 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2090 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2098 for (i = 0; i < MapInfo_count; ++i)
2100 if (MapInfo_Get_ByID(i))
2102 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
2105 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
2106 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2114 for (i = 0; i < MapInfo_count; ++i)
2116 if (MapInfo_Get_ByID(i))
2118 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
2121 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
2122 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
2128 MapInfo_ClearTemps();
2131 return "No records are available on this server.\n";
2133 return strcat("Records on this server:\n", s);
2136 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2139 vector start, org, delta, end, enddown, mstart;
2141 m = e.dphitcontentsmask;
2142 e.dphitcontentsmask = goodcontents | badcontents;
2145 delta = world.maxs - world.mins;
2147 for (i = 0; i < attempts; ++i)
2149 start_x = org_x + random() * delta_x;
2150 start_y = org_y + random() * delta_y;
2151 start_z = org_z + random() * delta_z;
2153 // rule 1: start inside world bounds, and outside
2154 // solid, and don't start from somewhere where you can
2155 // fall down to evil
2156 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2157 if (trace_fraction >= 1)
2159 if (trace_startsolid)
2161 if (trace_dphitcontents & badcontents)
2163 if (trace_dphitq3surfaceflags & badsurfaceflags)
2166 // rule 2: if we are too high, lower the point
2167 if (trace_fraction * delta_z > maxaboveground)
2168 start = trace_endpos + '0 0 1' * maxaboveground;
2169 enddown = trace_endpos;
2171 // rule 3: make sure we aren't outside the map. This only works
2172 // for somewhat well formed maps. A good rule of thumb is that
2173 // the map should have a convex outside hull.
2174 // these can be traceLINES as we already verified the starting box
2175 mstart = start + 0.5 * (e.mins + e.maxs);
2176 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2177 if (trace_fraction >= 1)
2179 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2180 if (trace_fraction >= 1)
2182 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2183 if (trace_fraction >= 1)
2185 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2186 if (trace_fraction >= 1)
2188 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2189 if (trace_fraction >= 1)
2192 // find a random vector to "look at"
2193 end_x = org_x + random() * delta_x;
2194 end_y = org_y + random() * delta_y;
2195 end_z = org_z + random() * delta_z;
2196 end = start + normalize(end - start) * vlen(delta);
2198 // rule 4: start TO end must not be too short
2199 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2200 if (trace_startsolid)
2202 if (trace_fraction < minviewdistance / vlen(delta))
2205 // rule 5: don't want to look at sky
2206 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2209 // rule 6: we must not end up in trigger_hurt
2210 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2212 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2219 e.dphitcontentsmask = m;
2223 setorigin(e, start);
2224 e.angles = vectoangles(end - start);
2225 dprint("Needed ", ftos(i + 1), " attempts\n");
2232 float zcurveparticles_effectno;
2233 vector zcurveparticles_start;
2234 float zcurveparticles_spd;
2236 void endzcurveparticles()
2238 if(zcurveparticles_effectno)
2241 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2243 zcurveparticles_effectno = 0;
2246 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2248 spd = bound(0, floor(spd / 16), 32767);
2249 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2251 endzcurveparticles();
2252 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2253 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2254 WriteShort(MSG_BROADCAST, effectno);
2255 WriteCoord(MSG_BROADCAST, start_x);
2256 WriteCoord(MSG_BROADCAST, start_y);
2257 WriteCoord(MSG_BROADCAST, start_z);
2258 zcurveparticles_effectno = effectno;
2259 zcurveparticles_start = start;
2262 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2263 WriteCoord(MSG_BROADCAST, end_x);
2264 WriteCoord(MSG_BROADCAST, end_y);
2265 WriteCoord(MSG_BROADCAST, end_z);
2266 WriteCoord(MSG_BROADCAST, end_dz);
2267 zcurveparticles_spd = spd;
2270 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2273 vector vecxy, velxy;
2275 vecxy = end - start;
2280 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2282 endzcurveparticles();
2283 trailparticles(world, effectno, start, end);
2287 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2288 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2291 string GetGametype(); // g_world.qc
2292 void write_recordmarker(entity pl, float tstart, float dt)
2294 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2296 // also write a marker into demo files for demotc-race-record-extractor to find
2299 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2300 " ", ftos(tstart), " ", ftos(dt), "\n"));
2303 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2305 switch(self.owner.cvar_cl_gunalign)
2316 if(allowcenter) // 2: allow center handedness
2329 if(allowcenter) // 2: allow center handedness
2345 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2350 if (cvar("g_shootfromeye"))
2354 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2362 else if (cvar("g_shootfromcenter"))
2366 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2374 else if (cvar("g_shootfromclient"))
2376 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2378 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2393 void attach_sameorigin(entity e, entity to, string tag)
2395 vector org, t_forward, t_left, t_up, e_forward, e_up;
2402 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2403 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2404 t_forward = v_forward * tagscale;
2405 t_left = v_right * -tagscale;
2406 t_up = v_up * tagscale;
2408 e.origin_x = org * t_forward;
2409 e.origin_y = org * t_left;
2410 e.origin_z = org * t_up;
2412 // current forward and up directions
2413 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2414 e.angles_x = -e.angles_x;
2415 fixedmakevectors(e.angles);
2417 // untransform forward, up!
2418 e_forward_x = v_forward * t_forward;
2419 e_forward_y = v_forward * t_left;
2420 e_forward_z = v_forward * t_up;
2421 e_up_x = v_up * t_forward;
2422 e_up_y = v_up * t_left;
2423 e_up_z = v_up * t_up;
2425 e.angles = fixedvectoangles2(e_forward, e_up);
2426 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2427 e.angles_x = -e.angles_x;
2429 setattachment(e, to, tag);
2430 setorigin(e, e.origin);
2433 void detach_sameorigin(entity e)
2436 org = gettaginfo(e, 0);
2437 e.angles = fixedvectoangles2(v_forward, v_up);
2438 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2439 e.angles_x = -e.angles_x;
2441 setattachment(e, world, "");
2442 setorigin(e, e.origin);
2445 void follow_sameorigin(entity e, entity to)
2447 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2448 e.aiment = to; // make the hole follow bmodel
2449 e.punchangle = to.angles; // the original angles of bmodel
2450 e.view_ofs = e.origin - to.origin; // relative origin
2451 e.v_angle = e.angles - to.angles; // relative angles
2454 void unfollow_sameorigin(entity e)
2456 e.movetype = MOVETYPE_NONE;
2459 entity gettaginfo_relative_ent;
2460 vector gettaginfo_relative(entity e, float tag)
2462 if (!gettaginfo_relative_ent)
2464 gettaginfo_relative_ent = spawn();
2465 gettaginfo_relative_ent.effects = EF_NODRAW;
2467 gettaginfo_relative_ent.model = e.model;
2468 gettaginfo_relative_ent.modelindex = e.modelindex;
2469 gettaginfo_relative_ent.frame = e.frame;
2470 return gettaginfo(gettaginfo_relative_ent, tag);
2473 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2477 if (pl.soundentity.cnt & p)
2479 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2480 pl.soundentity.cnt |= p;
2483 void SoundEntity_StopSound(entity pl, float chan)
2487 if (pl.soundentity.cnt & p)
2489 stopsoundto(MSG_ALL, pl.soundentity, chan);
2490 pl.soundentity.cnt &~= p;
2494 void SoundEntity_Attach(entity pl)
2496 pl.soundentity = spawn();
2497 pl.soundentity.classname = "soundentity";
2498 pl.soundentity.owner = pl;
2499 setattachment(pl.soundentity, pl, "");
2500 setmodel(pl.soundentity, "null");
2503 void SoundEntity_Detach(entity pl)
2506 for (i = 0; i <= 7; ++i)
2507 SoundEntity_StopSound(pl, i);
2511 float ParseCommandPlayerSlotTarget_firsttoken;
2512 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2520 ParseCommandPlayerSlotTarget_firsttoken = -1;
2524 if (substring(argv(idx), 0, 1) == "#")
2526 s = substring(argv(idx), 1, -1);
2534 ParseCommandPlayerSlotTarget_firsttoken = idx;
2535 if (s == ftos(stof(s)))
2537 e = edict_num(stof(s));
2538 if (e.flags & FL_CLIENT)
2544 // it must be a nick name
2547 ParseCommandPlayerSlotTarget_firsttoken = idx;
2550 FOR_EACH_CLIENT(head)
2551 if (head.netname == s)
2559 s = strdecolorize(s);
2561 FOR_EACH_CLIENT(head)
2562 if (strdecolorize(head.netname) == s)
2577 float modeleffect_SendEntity(entity to, float sf)
2580 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2583 if(self.velocity != '0 0 0')
2585 if(self.angles != '0 0 0')
2587 if(self.avelocity != '0 0 0')
2590 WriteByte(MSG_ENTITY, f);
2591 WriteShort(MSG_ENTITY, self.modelindex);
2592 WriteByte(MSG_ENTITY, self.skin);
2593 WriteByte(MSG_ENTITY, self.frame);
2594 WriteCoord(MSG_ENTITY, self.origin_x);
2595 WriteCoord(MSG_ENTITY, self.origin_y);
2596 WriteCoord(MSG_ENTITY, self.origin_z);
2599 WriteCoord(MSG_ENTITY, self.velocity_x);
2600 WriteCoord(MSG_ENTITY, self.velocity_y);
2601 WriteCoord(MSG_ENTITY, self.velocity_z);
2605 WriteCoord(MSG_ENTITY, self.angles_x);
2606 WriteCoord(MSG_ENTITY, self.angles_y);
2607 WriteCoord(MSG_ENTITY, self.angles_z);
2611 WriteCoord(MSG_ENTITY, self.avelocity_x);
2612 WriteCoord(MSG_ENTITY, self.avelocity_y);
2613 WriteCoord(MSG_ENTITY, self.avelocity_z);
2615 WriteShort(MSG_ENTITY, self.scale * 256.0);
2616 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2617 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2618 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2619 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2624 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)
2629 e.classname = "modeleffect";
2637 e.teleport_time = t1;
2641 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2645 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2648 sz = max(e.scale, e.scale2);
2649 setsize(e, e.mins * sz, e.maxs * sz);
2650 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2653 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2655 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2658 float randombit(float bits)
2660 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2669 for(f = 1; f <= bits; f *= 2)
2678 r = (r - 1) / (n - 1);
2685 float randombits(float bits, float k, float error_return)
2689 while(k > 0 && bits != r)
2691 r += randombit(bits - r);
2700 void randombit_test(float bits, float iter)
2704 print(ftos(randombit(bits)), "\n");
2709 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2711 if(halflifedist > 0)
2712 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2713 else if(halflifedist < 0)
2714 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);