1 var void remove(entity e);
2 void objerror(string s);
4 .vector dropped_origin;
6 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
8 string ColoredTeamName(float t);
10 float DistributeEvenly_amount;
11 float DistributeEvenly_totalweight;
12 void DistributeEvenly_Init(float amount, float totalweight)
14 if (DistributeEvenly_amount)
16 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
17 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
20 DistributeEvenly_amount = 0;
22 DistributeEvenly_amount = amount;
23 DistributeEvenly_totalweight = totalweight;
25 float DistributeEvenly_Get(float weight)
30 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
31 DistributeEvenly_totalweight -= weight;
32 DistributeEvenly_amount -= f;
36 void move_out_of_solid_expand(entity e, vector by)
39 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
42 if (trace_fraction < 1)
45 // adjust origin in the other direction...
46 e.origin = e.origin - by * (1 - trace_fraction);
50 float move_out_of_solid(entity e)
55 traceline(o, o, MOVE_WORLDONLY, e);
59 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
60 if (!trace_startsolid)
67 move_out_of_solid_expand(e, '1 0 0' * m0_x);
69 move_out_of_solid_expand(e, '1 0 0' * m1_x);
71 move_out_of_solid_expand(e, '0 1 0' * m0_y);
73 move_out_of_solid_expand(e, '0 1 0' * m1_y);
75 move_out_of_solid_expand(e, '0 0 1' * m0_z);
77 move_out_of_solid_expand(e, '0 0 1' * m1_z);
79 setorigin(e, e.origin);
81 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
91 string STR_PLAYER = "player";
92 string STR_SPECTATOR = "spectator";
93 string STR_OBSERVER = "observer";
96 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
97 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
98 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
99 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
101 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
102 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
103 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
104 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
105 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
108 // copies a string to a tempstring (so one can strunzone it)
109 string strcat1(string s) = #115; // FRIK_FILE
114 void bcenterprint(string s)
116 // TODO replace by MSG_ALL (would show it to spectators too, though)?
118 FOR_EACH_PLAYER(head)
119 if (clienttype(head) == CLIENTTYPE_REAL)
120 centerprint(head, s);
123 void GameLogEcho(string s)
128 if (cvar("sv_eventlog_files"))
133 matches = cvar("sv_eventlog_files_counter") + 1;
134 cvar_set("sv_eventlog_files_counter", ftos(matches));
137 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
138 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
139 logfile = fopen(fn, FILE_APPEND);
140 fputs(logfile, ":logversion:3\n");
144 if (cvar("sv_eventlog_files_timestamps"))
145 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
147 fputs(logfile, strcat(s, "\n"));
150 if (cvar("sv_eventlog_console"))
159 // will be opened later
164 if (logfile_open && logfile >= 0)
171 float spawnpoint_nag;
172 void relocate_spawnpoint()
174 // nudge off the floor
175 setorigin(self, self.origin + '0 0 1');
177 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
178 if (trace_startsolid)
184 if (!move_out_of_solid(self))
185 objerror("could not get out of solid at all!");
186 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
187 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
188 print(" ", ftos(self.origin_y - o_y));
189 print(" ", ftos(self.origin_z - o_z), "'\n");
190 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
193 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
199 self.mins = self.maxs = '0 0 0';
200 objerror("player spawn point in solid, mapper sucks!\n");
205 if (cvar("g_spawnpoints_autodrop"))
207 setsize(self, PL_MIN, PL_MAX);
211 self.use = spawnpoint_use;
212 self.team_saved = self.team;
216 if (g_ctf || g_assault || g_onslaught || g_domination || g_nexball)
218 have_team_spawns = 1;
220 if (cvar("r_showbboxes"))
222 // show where spawnpoints point at too
223 makevectors(self.angles);
226 e.classname = "info_player_foo";
227 setorigin(e, self.origin + v_forward * 24);
228 setsize(e, '-8 -8 -8', '8 8 8');
229 e.solid = SOLID_TRIGGER;
233 #define strstr strstrofs
235 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
236 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
237 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
238 // BE CONSTANT OR strzoneD!
239 float strstr(string haystack, string needle, float offset)
243 len = strlen(needle);
244 endpos = strlen(haystack) - len;
245 while(offset <= endpos)
247 found = substring(haystack, offset, len);
256 float NUM_NEAREST_ENTITIES = 4;
257 entity nearest_entity[NUM_NEAREST_ENTITIES];
258 float nearest_length[NUM_NEAREST_ENTITIES];
259 entity findnearest(vector point, .string field, string value, vector axismod)
270 localhead = find(world, field, value);
273 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
274 dist = localhead.oldorigin;
276 dist = localhead.origin;
278 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
281 for (i = 0; i < num_nearest; ++i)
283 if (len < nearest_length[i])
287 // now i tells us where to insert at
288 // INSERTION SORT! YOU'VE SEEN IT! RUN!
289 if (i < NUM_NEAREST_ENTITIES)
291 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
293 nearest_length[j + 1] = nearest_length[j];
294 nearest_entity[j + 1] = nearest_entity[j];
296 nearest_length[i] = len;
297 nearest_entity[i] = localhead;
298 if (num_nearest < NUM_NEAREST_ENTITIES)
299 num_nearest = num_nearest + 1;
302 localhead = find(localhead, field, value);
305 // now use the first one from our list that we can see
306 for (i = 0; i < num_nearest; ++i)
308 traceline(point, nearest_entity[i].origin, TRUE, world);
309 if (trace_fraction == 1)
313 dprint("Nearest point (");
314 dprint(nearest_entity[0].netname);
315 dprint(") is not visible, using a visible one.\n");
317 return nearest_entity[i];
321 if (num_nearest == 0)
324 dprint("Not seeing any location point, using nearest as fallback.\n");
326 dprint("Candidates were: ");
327 for(j = 0; j < num_nearest; ++j)
331 dprint(nearest_entity[j].netname);
336 return nearest_entity[0];
339 void spawnfunc_target_location()
341 self.classname = "target_location";
342 // location name in netname
343 // eventually support: count, teamgame selectors, line of sight?
346 void spawnfunc_info_location()
348 self.classname = "target_location";
349 self.message = self.netname;
352 string NearestLocation(vector p)
357 loc = findnearest(p, classname, "target_location", '1 1 1');
364 loc = findnearest(p, target, "###item###", '1 1 4');
371 string formatmessage(string msg)
382 break; // too many replacements
384 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
385 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
395 replacement = substring(msg, p, 2);
396 escape = substring(msg, p + 1, 1);
399 else if (escape == "\\")
401 else if (escape == "n")
403 else if (escape == "a")
404 replacement = ftos(floor(self.armorvalue));
405 else if (escape == "h")
406 replacement = ftos(floor(self.health));
407 else if (escape == "l")
408 replacement = NearestLocation(self.origin);
409 else if (escape == "y")
410 replacement = NearestLocation(self.cursor_trace_endpos);
411 else if (escape == "d")
412 replacement = NearestLocation(self.death_origin);
413 else if (escape == "w")
418 wep = self.switchweapon;
421 replacement = W_Name(wep);
423 else if (escape == "W")
425 if (self.items & IT_SHELLS) replacement = "shells";
426 else if (self.items & IT_NAILS) replacement = "bullets";
427 else if (self.items & IT_ROCKETS) replacement = "rockets";
428 else if (self.items & IT_CELLS) replacement = "cells";
429 else replacement = "batteries"; // ;)
431 else if (escape == "x")
433 replacement = self.cursor_trace_ent.netname;
434 if (!replacement || !self.cursor_trace_ent)
435 replacement = "nothing";
437 else if (escape == "p")
439 if (self.last_selected_player)
440 replacement = self.last_selected_player.netname;
442 replacement = "(nobody)";
444 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
445 p = p + strlen(replacement);
456 >0: receives a cvar from name=argv(f) value=argv(f+1)
458 void GetCvars_handleString(string thisname, float f, .string field, string name)
463 strunzone(self.field);
464 self.field = string_null;
468 if (thisname == name)
471 strunzone(self.field);
472 self.field = strzone(argv(f + 1));
476 stuffcmd(self, strcat("sendcvar ", name, "\n"));
478 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
480 GetCvars_handleString(thisname, f, field, name);
481 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
482 if (thisname == name)
485 s = func(strcat1(self.field));
488 strunzone(self.field);
489 self.field = strzone(s);
493 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
500 if (thisname == name)
501 self.field = stof(argv(f + 1));
504 stuffcmd(self, strcat("sendcvar ", name, "\n"));
506 string W_FixWeaponOrder_ForceComplete(string s);
507 string W_FixWeaponOrder_AllowIncomplete(string s);
508 float w_getbestweapon(entity e);
509 void GetCvars(float f)
513 s = strcat1(argv(f));
514 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
515 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
516 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
517 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
518 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
519 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
520 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
521 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
522 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
523 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
524 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
525 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
526 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
527 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
528 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
529 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
530 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
531 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
532 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
533 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
534 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
535 #ifdef ALLOW_FORCEMODELS
536 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
537 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
539 GetCvars_handleFloat(s, f, cvar_cl_gunalign, "cl_gunalign");
542 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
545 if (s == "cl_weaponpriority")
546 self.switchweapon = w_getbestweapon(self);
550 float fexists(string f)
553 fh = fopen(f, FILE_READ);
560 void backtrace(string msg)
563 dev = cvar("developer");
564 cvar_set("developer", "1");
566 dprint("--- CUT HERE ---\nWARNING: ");
569 remove(world); // isn't there any better way to cause a backtrace?
570 dprint("\n--- CUT UNTIL HERE ---\n");
571 cvar_set("developer", ftos(dev));
574 string Team_ColorCode(float teamid)
576 if (teamid == COLOR_TEAM1)
578 else if (teamid == COLOR_TEAM2)
580 else if (teamid == COLOR_TEAM3)
582 else if (teamid == COLOR_TEAM4)
587 string Team_ColorName(float t)
589 // fixme: Search for team entities and get their .netname's!
590 if (t == COLOR_TEAM1)
592 if (t == COLOR_TEAM2)
594 if (t == COLOR_TEAM3)
596 if (t == COLOR_TEAM4)
600 string Team_ColorNameLowerCase(float t)
602 // fixme: Search for team entities and get their .netname's!
603 if (t == COLOR_TEAM1)
605 if (t == COLOR_TEAM2)
607 if (t == COLOR_TEAM3)
609 if (t == COLOR_TEAM4)
614 #define CENTERPRIO_POINT 1
615 #define CENTERPRIO_SPAM 2
616 #define CENTERPRIO_VOTE 4
617 #define CENTERPRIO_NORMAL 5
618 #define CENTERPRIO_SHIELDING 7
619 #define CENTERPRIO_MAPVOTE 9
620 #define CENTERPRIO_IDLEKICK 50
621 #define CENTERPRIO_ADMIN 99
622 .float centerprint_priority;
623 .float centerprint_expires;
624 void centerprint_atprio(entity e, float prio, string s)
626 if (intermission_running)
627 if (prio < CENTERPRIO_MAPVOTE)
629 if (time > e.centerprint_expires)
630 e.centerprint_priority = 0;
631 if (prio >= e.centerprint_priority)
633 e.centerprint_priority = prio;
634 if (timeoutStatus == 2)
635 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
637 e.centerprint_expires = time + e.cvar_scr_centertime;
638 centerprint_builtin(e, s);
641 void centerprint_expire(entity e, float prio)
643 if (prio == e.centerprint_priority)
645 e.centerprint_priority = 0;
646 centerprint_builtin(e, "");
649 void centerprint(entity e, string s)
651 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
654 // decolorizes and team colors the player name when needed
655 string playername(entity p)
658 if (teams_matter && !intermission_running && p.classname == "player")
660 t = Team_ColorCode(p.team);
661 return strcat(t, strdecolorize(p.netname));
667 vector randompos(vector m1, vector m2)
671 v_x = m2_x * random() + m1_x;
672 v_y = m2_y * random() + m1_y;
673 v_z = m2_z * random() + m1_z;
677 float g_pickup_shells;
678 float g_pickup_shells_max;
679 float g_pickup_nails;
680 float g_pickup_nails_max;
681 float g_pickup_rockets;
682 float g_pickup_rockets_max;
683 float g_pickup_cells;
684 float g_pickup_cells_max;
686 float g_pickup_fuel_jetpack;
687 float g_pickup_fuel_max;
688 float g_pickup_armorsmall;
689 float g_pickup_armorsmall_max;
690 float g_pickup_armormedium;
691 float g_pickup_armormedium_max;
692 float g_pickup_armorbig;
693 float g_pickup_armorbig_max;
694 float g_pickup_armorlarge;
695 float g_pickup_armorlarge_max;
696 float g_pickup_healthsmall;
697 float g_pickup_healthsmall_max;
698 float g_pickup_healthmedium;
699 float g_pickup_healthmedium_max;
700 float g_pickup_healthlarge;
701 float g_pickup_healthlarge_max;
702 float g_pickup_healthmega;
703 float g_pickup_healthmega_max;
705 string g_weaponarena_list;
706 float g_weaponspeedfactor;
707 float g_weapondamagefactor;
708 float g_weaponforcefactor;
712 float start_ammo_shells;
713 float start_ammo_nails;
714 float start_ammo_rockets;
715 float start_ammo_cells;
716 float start_ammo_fuel;
718 float start_armorvalue;
719 float warmup_start_weapons;
720 float warmup_start_ammo_shells;
721 float warmup_start_ammo_nails;
722 float warmup_start_ammo_rockets;
723 float warmup_start_ammo_cells;
724 float warmup_start_ammo_fuel;
725 float warmup_start_health;
726 float warmup_start_armorvalue;
729 entity get_weaponinfo(float w);
731 float NixNex_CanChooseWeapon(float wpn);
732 void readplayerstartcvars()
738 // initialize starting values for players
741 start_ammo_shells = 0;
742 start_ammo_nails = 0;
743 start_ammo_rockets = 0;
744 start_ammo_cells = 0;
745 start_health = cvar("g_balance_health_start");
746 start_armorvalue = cvar("g_balance_armor_start");
749 s = cvar_string("g_weaponarena");
755 g_weaponarena_list = "All Weapons";
756 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
758 e = get_weaponinfo(j);
759 g_weaponarena |= e.weapons;
760 weapon_action(e.weapon, WR_PRECACHE);
763 else if (s == "most")
765 g_weaponarena_list = "Most Weapons";
766 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
768 e = get_weaponinfo(j);
769 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
771 g_weaponarena |= e.weapons;
772 weapon_action(e.weapon, WR_PRECACHE);
776 else if (s == "none")
778 g_weaponarena_list = "No Weapons";
779 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
783 t = tokenize_console(s);
784 g_weaponarena_list = "";
785 for (i = 0; i < t; ++i)
788 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
790 e = get_weaponinfo(j);
793 g_weaponarena |= e.weapons;
794 weapon_action(e.weapon, WR_PRECACHE);
795 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
801 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
804 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
810 // will be done later
811 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
812 if (NixNex_CanChooseWeapon(i))
813 weapon_action(i, WR_PRECACHE);
814 if(!cvar("g_use_ammunition"))
815 start_items |= IT_UNLIMITED_AMMO;
817 else if (g_weaponarena)
819 start_weapons = g_weaponarena;
820 start_ammo_rockets = 999;
821 start_ammo_shells = 999;
822 start_ammo_cells = 999;
823 start_ammo_nails = 999;
824 start_ammo_fuel = 999;
825 start_items |= IT_UNLIMITED_AMMO;
827 else if (g_minstagib)
830 start_armorvalue = 0;
831 start_weapons = WEPBIT_MINSTANEX;
832 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
833 start_ammo_cells = cvar("g_minstagib_ammo_start");
834 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
835 start_ammo_fuel = cvar("g_start_ammo_fuel");
837 if (g_minstagib_invis_alpha <= 0)
838 g_minstagib_invis_alpha = -1;
844 start_ammo_shells = cvar("g_lms_start_ammo_shells");
845 start_ammo_nails = cvar("g_lms_start_ammo_nails");
846 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
847 start_ammo_cells = cvar("g_lms_start_ammo_cells");
848 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
849 start_health = cvar("g_lms_start_health");
850 start_armorvalue = cvar("g_lms_start_armor");
852 else if (cvar("g_use_ammunition"))
854 start_ammo_shells = cvar("g_start_ammo_shells");
855 start_ammo_nails = cvar("g_start_ammo_nails");
856 start_ammo_rockets = cvar("g_start_ammo_rockets");
857 start_ammo_cells = cvar("g_start_ammo_cells");
858 start_ammo_fuel = cvar("g_start_ammo_fuel");
862 start_ammo_shells = cvar("g_pickup_shells_max");
863 start_ammo_nails = cvar("g_pickup_nails_max");
864 start_ammo_rockets = cvar("g_pickup_rockets_max");
865 start_ammo_cells = cvar("g_pickup_cells_max");
866 start_ammo_fuel = cvar("g_pickup_fuel_max");
867 start_items |= IT_UNLIMITED_AMMO;
870 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
872 e = get_weaponinfo(i);
876 t = cvar(strcat("g_start_weapon_", e.netname));
878 if (t < 0) // "default" weapon selection
881 t = (e.spawnflags & WEPSPAWNFLAG_NORMAL);
882 else if (g_race || g_cts)
883 t = (i == WEP_LASER);
885 t = 0; // weapon is set a few lines later
887 t = (i == WEP_LASER || i == WEP_SHOTGUN);
888 if (g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
889 t += (i == WEP_HOOK);
892 if (g_nexball && i == WEP_PORTO)
897 start_weapons |= e.weapons;
898 weapon_action(e.weapon, WR_PRECACHE);
905 warmup_start_ammo_shells = start_ammo_shells;
906 warmup_start_ammo_nails = start_ammo_nails;
907 warmup_start_ammo_rockets = start_ammo_rockets;
908 warmup_start_ammo_cells = start_ammo_cells;
909 warmup_start_health = start_health;
910 warmup_start_armorvalue = start_armorvalue;
911 warmup_start_weapons = start_weapons;
913 if (!g_weaponarena && !g_nixnex && !g_minstagib)
915 if (cvar("g_use_ammunition"))
917 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
918 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
919 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
920 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
922 warmup_start_health = cvar("g_warmup_start_health");
923 warmup_start_armorvalue = cvar("g_warmup_start_armor");
924 if (cvar("g_warmup_allguns"))
926 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
928 e = get_weaponinfo(i);
931 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
933 warmup_start_weapons |= e.weapons;
934 weapon_action(e.weapon, WR_PRECACHE);
941 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
943 g_grappling_hook = 0; // these two can't coexist, as they use the same button
944 start_items |= IT_FUEL_REGEN;
945 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
949 start_items |= IT_JETPACK;
951 if (g_weapon_stay == 2)
953 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
954 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
955 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
956 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
957 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
958 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
959 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
960 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
961 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
962 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
965 start_ammo_shells = max(0, start_ammo_shells);
966 start_ammo_nails = max(0, start_ammo_nails);
967 start_ammo_cells = max(0, start_ammo_cells);
968 start_ammo_rockets = max(0, start_ammo_rockets);
969 start_ammo_fuel = max(0, start_ammo_fuel);
971 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
972 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
973 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
974 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
975 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
979 float g_bugrigs_planar_movement;
980 float g_bugrigs_planar_movement_car_jumping;
981 float g_bugrigs_reverse_spinning;
982 float g_bugrigs_reverse_speeding;
983 float g_bugrigs_reverse_stopping;
984 float g_bugrigs_air_steering;
985 float g_bugrigs_angle_smoothing;
986 float g_bugrigs_friction_floor;
987 float g_bugrigs_friction_brake;
988 float g_bugrigs_friction_air;
989 float g_bugrigs_accel;
990 float g_bugrigs_speed_ref;
991 float g_bugrigs_speed_pow;
992 float g_bugrigs_steer;
994 float g_touchexplode;
995 float g_touchexplode_radius;
996 float g_touchexplode_damage;
997 float g_touchexplode_edgedamage;
998 float g_touchexplode_force;
1000 void readlevelcvars(void)
1002 g_bugrigs = cvar("g_bugrigs");
1003 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1004 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1005 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1006 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1007 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1008 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1009 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1010 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1011 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1012 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1013 g_bugrigs_accel = cvar("g_bugrigs_accel");
1014 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1015 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1016 g_bugrigs_steer = cvar("g_bugrigs_steer");
1018 g_touchexplode = cvar("g_touchexplode");
1019 g_touchexplode_radius = cvar("g_touchexplode_radius");
1020 g_touchexplode_damage = cvar("g_touchexplode_damage");
1021 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1022 g_touchexplode_force = cvar("g_touchexplode_force");
1024 #ifdef ALLOW_FORCEMODELS
1025 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1027 sv_loddistance1 = cvar("sv_loddistance1");
1028 sv_loddistance2 = cvar("sv_loddistance2");
1029 if(sv_loddistance2 <= sv_loddistance1)
1030 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1031 sv_clones = cvar("sv_clones");
1032 sv_cheats = cvar("sv_cheats");
1033 sv_gentle = cvar("sv_gentle");
1034 sv_foginterval = cvar("sv_foginterval");
1035 g_cloaked = cvar("g_cloaked");
1036 g_jump_grunt = cvar("g_jump_grunt");
1037 g_footsteps = cvar("g_footsteps");
1038 g_grappling_hook = cvar("g_grappling_hook");
1039 g_jetpack = cvar("g_jetpack");
1040 g_laserguided_missile = cvar("g_laserguided_missile");
1041 g_midair = cvar("g_midair");
1042 g_minstagib = cvar("g_minstagib");
1043 g_nixnex = cvar("g_nixnex");
1044 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1045 g_norecoil = cvar("g_norecoil");
1046 g_vampire = cvar("g_vampire");
1047 g_bloodloss = cvar("g_bloodloss");
1048 sv_maxidle = cvar("sv_maxidle");
1049 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1050 sv_pogostick = cvar("sv_pogostick");
1051 sv_doublejump = cvar("sv_doublejump");
1052 g_ctf_reverse = cvar("g_ctf_reverse");
1054 inWarmupStage = cvar("g_warmup");
1055 g_warmup_limit = cvar("g_warmup_limit");
1056 g_warmup_allguns = cvar("g_warmup_allguns");
1057 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1059 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
1060 inWarmupStage = 0; // these modes cannot work together, sorry
1062 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1063 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1064 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1065 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1066 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1067 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1068 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1069 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1070 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1071 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1072 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1073 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1075 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1076 if (g_nixnex) g_weaponarena = 0;
1079 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1080 g_weapondamagefactor = cvar("g_weapondamagefactor");
1081 g_weaponforcefactor = cvar("g_weaponforcefactor");
1083 g_pickup_shells = cvar("g_pickup_shells");
1084 g_pickup_shells_max = cvar("g_pickup_shells_max");
1085 g_pickup_nails = cvar("g_pickup_nails");
1086 g_pickup_nails_max = cvar("g_pickup_nails_max");
1087 g_pickup_rockets = cvar("g_pickup_rockets");
1088 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1089 g_pickup_cells = cvar("g_pickup_cells");
1090 g_pickup_cells_max = cvar("g_pickup_cells_max");
1091 g_pickup_fuel = cvar("g_pickup_fuel");
1092 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1093 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1094 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1095 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1096 g_pickup_armormedium = cvar("g_pickup_armormedium");
1097 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1098 g_pickup_armorbig = cvar("g_pickup_armorbig");
1099 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1100 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1101 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1102 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1103 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1104 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1105 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1106 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1107 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1108 g_pickup_healthmega = cvar("g_pickup_healthmega");
1109 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1111 g_pinata = cvar("g_pinata");
1113 g_weapon_stay = cvar("g_weapon_stay");
1114 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1117 if not(inWarmupStage)
1118 game_starttime = cvar("g_start_delay");
1120 readplayerstartcvars();
1124 // TODO sound pack system
1127 string precache_sound_builtin (string s) = #19;
1128 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1129 string precache_sound(string s)
1131 return precache_sound_builtin(strcat(soundpack, s));
1133 void play2(entity e, string filename)
1135 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1137 void sound(entity e, float chan, string samp, float vol, float atten)
1139 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1144 string precache_sound (string s) = #19;
1145 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1146 float precache_sound_index (string s) = #19;
1148 #define SND_VOLUME 1
1149 #define SND_ATTENUATION 2
1150 #define SND_LARGEENTITY 8
1151 #define SND_LARGESOUND 16
1153 float sound_allowed(float dest, entity e)
1155 // sounds from world may always pass
1158 if (e.classname == "body")
1160 if (e.owner && e.owner != e)
1165 // sounds to self may always pass
1166 if (dest == MSG_ONE)
1167 if (e == msg_entity)
1169 // sounds by players can be removed
1170 if (cvar("bot_sound_monopoly"))
1171 if (clienttype(e) == CLIENTTYPE_REAL)
1173 // anything else may pass
1177 void sound(entity e, float chan, string samp, float vol, float atten)
1179 if (!sound_allowed(MSG_BROADCAST, e))
1181 sound_builtin(e, chan, samp, vol, atten);
1183 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1187 if (!sound_allowed(dest, e))
1190 entno = num_for_edict(e);
1191 idx = precache_sound_index(samp);
1196 atten = floor(atten * 64);
1197 vol = floor(vol * 255);
1200 sflags |= SND_VOLUME;
1202 sflags |= SND_ATTENUATION;
1204 sflags |= SND_LARGEENTITY;
1206 sflags |= SND_LARGESOUND;
1208 WriteByte(dest, SVC_SOUND);
1209 WriteByte(dest, sflags);
1210 if (sflags & SND_VOLUME)
1211 WriteByte(dest, vol);
1212 if (sflags & SND_ATTENUATION)
1213 WriteByte(dest, atten);
1214 if (sflags & SND_LARGEENTITY)
1216 WriteShort(dest, entno);
1217 WriteByte(dest, chan);
1221 WriteShort(dest, entno * 8 + chan);
1223 if (sflags & SND_LARGESOUND)
1224 WriteShort(dest, idx);
1226 WriteByte(dest, idx);
1228 WriteCoord(dest, o_x);
1229 WriteCoord(dest, o_y);
1230 WriteCoord(dest, o_z);
1232 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1236 if (!sound_allowed(dest, e))
1239 o = e.origin + 0.5 * (e.mins + e.maxs);
1240 soundtoat(dest, e, o, chan, samp, vol, atten);
1242 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1244 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1246 void stopsoundto(float dest, entity e, float chan)
1250 if (!sound_allowed(dest, e))
1253 entno = num_for_edict(e);
1258 idx = precache_sound_index("misc/null.wav");
1259 sflags = SND_LARGEENTITY;
1261 sflags |= SND_LARGESOUND;
1262 WriteByte(dest, SVC_SOUND);
1263 WriteByte(dest, sflags);
1264 WriteShort(dest, entno);
1265 WriteByte(dest, chan);
1266 if (sflags & SND_LARGESOUND)
1267 WriteShort(dest, idx);
1269 WriteByte(dest, idx);
1270 WriteCoord(dest, e.origin_x);
1271 WriteCoord(dest, e.origin_y);
1272 WriteCoord(dest, e.origin_z);
1276 WriteByte(dest, SVC_STOPSOUND);
1277 WriteShort(dest, entno * 8 + chan);
1280 void stopsound(entity e, float chan)
1282 if (!sound_allowed(MSG_BROADCAST, e))
1285 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1286 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1289 void play2(entity e, string filename)
1291 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1293 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1296 .float announcetime;
1297 float announce(entity player, string msg)
1299 if (time > player.announcetime)
1300 if (clienttype(player) == CLIENTTYPE_REAL)
1302 player.announcetime = time + 0.8;
1308 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1309 float spamsound(entity e, float chan, string samp, float vol, float atten)
1311 if (!sound_allowed(MSG_BROADCAST, e))
1314 if (time > e.announcetime)
1316 e.announcetime = time;
1317 sound(e, chan, samp, vol, atten);
1323 void play2team(float t, string filename)
1327 if (cvar("bot_sound_monopoly"))
1330 FOR_EACH_REALPLAYER(head)
1333 play2(head, filename);
1337 void play2all(string samp)
1339 if (cvar("bot_sound_monopoly"))
1342 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1345 void PrecachePlayerSounds(string f);
1346 void precache_all_models(string pattern)
1348 float globhandle, i, n;
1351 globhandle = search_begin(pattern, TRUE, FALSE);
1354 n = search_getsize(globhandle);
1355 for (i = 0; i < n; ++i)
1357 //print(search_getfilename(globhandle, i), "\n");
1358 f = search_getfilename(globhandle, i);
1361 if(substring(f, -9,5) == "_lod1")
1363 if(substring(f, -9,5) == "_lod2")
1365 if(!sv_loddistance1)
1367 PrecachePlayerSounds(strcat(f, ".sounds"));
1369 search_end(globhandle);
1374 // gamemode related things
1375 precache_model ("models/misc/chatbubble.spr");
1376 precache_model ("models/misc/teambubble.spr");
1379 precache_model ("models/runematch/curse.mdl");
1380 precache_model ("models/runematch/rune.mdl");
1383 #ifdef TTURRETS_ENABLED
1384 if (cvar("g_turrets"))
1388 // Precache all player models if desired
1389 if (cvar("sv_precacheplayermodels"))
1391 PrecachePlayerSounds("sound/player/default.sounds");
1392 precache_all_models("models/player/*.zym");
1393 precache_all_models("models/player/*.dpm");
1394 precache_all_models("models/player/*.md3");
1395 precache_all_models("models/player/*.psk");
1396 //precache_model("models/player/carni.zym");
1397 //precache_model("models/player/crash.zym");
1398 //precache_model("models/player/grunt.zym");
1399 //precache_model("models/player/headhunter.zym");
1400 //precache_model("models/player/insurrectionist.zym");
1401 //precache_model("models/player/jeandarc.zym");
1402 //precache_model("models/player/lurk.zym");
1403 //precache_model("models/player/lycanthrope.zym");
1404 //precache_model("models/player/marine.zym");
1405 //precache_model("models/player/nexus.zym");
1406 //precache_model("models/player/pyria.zym");
1407 //precache_model("models/player/shock.zym");
1408 //precache_model("models/player/skadi.zym");
1409 //precache_model("models/player/specop.zym");
1410 //precache_model("models/player/visitant.zym");
1413 if (cvar("sv_defaultcharacter"))
1416 s = cvar_string("sv_defaultplayermodel_red");
1420 PrecachePlayerSounds(strcat(s, ".sounds"));
1422 s = cvar_string("sv_defaultplayermodel_blue");
1426 PrecachePlayerSounds(strcat(s, ".sounds"));
1428 s = cvar_string("sv_defaultplayermodel_yellow");
1432 PrecachePlayerSounds(strcat(s, ".sounds"));
1434 s = cvar_string("sv_defaultplayermodel_pink");
1438 PrecachePlayerSounds(strcat(s, ".sounds"));
1440 s = cvar_string("sv_defaultplayermodel");
1444 PrecachePlayerSounds(strcat(s, ".sounds"));
1450 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1451 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1454 // gore and miscellaneous sounds
1455 //precache_sound ("misc/h2ohit.wav");
1456 precache_model ("models/hook.md3");
1457 precache_sound ("misc/armorimpact.wav");
1458 precache_sound ("misc/bodyimpact1.wav");
1459 precache_sound ("misc/bodyimpact2.wav");
1460 precache_sound ("misc/gib.wav");
1461 precache_sound ("misc/gib_splat01.wav");
1462 precache_sound ("misc/gib_splat02.wav");
1463 precache_sound ("misc/gib_splat03.wav");
1464 precache_sound ("misc/gib_splat04.wav");
1465 precache_sound ("misc/hit.wav");
1466 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1467 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1468 precache_sound ("misc/null.wav");
1469 precache_sound ("misc/spawn.wav");
1470 precache_sound ("misc/talk.wav");
1471 precache_sound ("misc/teleport.wav");
1472 precache_sound ("misc/poweroff.wav");
1473 precache_sound ("player/lava.wav");
1474 precache_sound ("player/slime.wav");
1477 precache_sound ("misc/jetpack_fly.wav");
1479 // announcer sounds - male
1480 precache_sound ("announcer/male/electrobitch.wav");
1481 precache_sound ("announcer/male/airshot.wav");
1482 precache_sound ("announcer/male/03kills.wav");
1483 precache_sound ("announcer/male/05kills.wav");
1484 precache_sound ("announcer/male/10kills.wav");
1485 precache_sound ("announcer/male/15kills.wav");
1486 precache_sound ("announcer/male/20kills.wav");
1487 precache_sound ("announcer/male/25kills.wav");
1488 precache_sound ("announcer/male/30kills.wav");
1489 precache_sound ("announcer/male/botlike.wav");
1490 precache_sound ("announcer/male/yoda.wav");
1491 precache_sound ("announcer/male/amazing.wav");
1492 precache_sound ("announcer/male/awesome.wav");
1493 precache_sound ("announcer/male/headshot.wav");
1494 precache_sound ("announcer/male/impressive.wav");
1496 // announcer sounds - robotic
1497 precache_sound ("announcer/robotic/prepareforbattle.wav");
1498 precache_sound ("announcer/robotic/begin.wav");
1499 precache_sound ("announcer/robotic/timeoutcalled.wav");
1500 precache_sound ("announcer/robotic/1fragleft.wav");
1501 precache_sound ("announcer/robotic/2fragsleft.wav");
1502 precache_sound ("announcer/robotic/3fragsleft.wav");
1505 precache_sound ("announcer/robotic/lastsecond.wav");
1506 precache_sound ("announcer/robotic/narrowly.wav");
1509 precache_model ("models/sprites/0.spr32");
1510 precache_model ("models/sprites/1.spr32");
1511 precache_model ("models/sprites/2.spr32");
1512 precache_model ("models/sprites/3.spr32");
1513 precache_model ("models/sprites/4.spr32");
1514 precache_model ("models/sprites/5.spr32");
1515 precache_model ("models/sprites/6.spr32");
1516 precache_model ("models/sprites/7.spr32");
1517 precache_model ("models/sprites/8.spr32");
1518 precache_model ("models/sprites/9.spr32");
1519 precache_model ("models/sprites/10.spr32");
1520 precache_sound ("announcer/robotic/1.wav");
1521 precache_sound ("announcer/robotic/2.wav");
1522 precache_sound ("announcer/robotic/3.wav");
1523 precache_sound ("announcer/robotic/4.wav");
1524 precache_sound ("announcer/robotic/5.wav");
1525 precache_sound ("announcer/robotic/6.wav");
1526 precache_sound ("announcer/robotic/7.wav");
1527 precache_sound ("announcer/robotic/8.wav");
1528 precache_sound ("announcer/robotic/9.wav");
1529 precache_sound ("announcer/robotic/10.wav");
1531 // common weapon precaches
1532 precache_sound ("weapons/weapon_switch.wav");
1533 precache_sound ("weapons/weaponpickup.wav");
1534 precache_sound ("weapons/unavailable.wav");
1535 if (g_grappling_hook)
1537 precache_sound ("weapons/hook_fire.wav"); // hook
1538 precache_sound ("weapons/hook_impact.wav"); // hook
1541 if (cvar("sv_precacheweapons") || g_nixnex)
1543 //precache weapon models/sounds
1546 while (wep <= WEP_LAST)
1548 weapon_action(wep, WR_PRECACHE);
1553 precache_model("models/elaser.mdl");
1554 precache_model("models/laser.mdl");
1555 precache_model("models/ebomb.mdl");
1558 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1560 if (!self.noise && self.music) // quake 3 uses the music field
1561 self.noise = self.music;
1563 // plays music for the level if there is any
1566 precache_sound (self.noise);
1567 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1572 // sorry, but using \ in macros breaks line numbers
1573 #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
1574 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1575 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1577 vector ExactTriggerHit_mins;
1578 vector ExactTriggerHit_maxs;
1579 float ExactTriggerHit_Recurse()
1585 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1588 if (trace_ent == self)
1593 se.solid = SOLID_NOT;
1594 f = ExactTriggerHit_Recurse();
1600 float ExactTriggerHit()
1604 if not(self.modelindex)
1608 self.solid = SOLID_BSP;
1609 ExactTriggerHit_mins = other.absmin;
1610 ExactTriggerHit_maxs = other.absmax;
1611 f = ExactTriggerHit_Recurse();
1617 // WARNING: this kills the trace globals
1618 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1619 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1621 #define INITPRIO_FIRST 0
1622 #define INITPRIO_GAMETYPE 0
1623 #define INITPRIO_GAMETYPE_FALLBACK 1
1624 #define INITPRIO_CVARS 5
1625 #define INITPRIO_FINDTARGET 10
1626 #define INITPRIO_DROPTOFLOOR 20
1627 #define INITPRIO_SETLOCATION 90
1628 #define INITPRIO_LINKDOORS 91
1629 #define INITPRIO_LAST 99
1631 .void(void) initialize_entity;
1632 .float initialize_entity_order;
1633 .entity initialize_entity_next;
1634 entity initialize_entity_first;
1636 void make_safe_for_remove(entity e)
1638 if (e.initialize_entity)
1641 for (ent = initialize_entity_first; ent; )
1643 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1645 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1646 // skip it in linked list
1649 prev.initialize_entity_next = ent.initialize_entity_next;
1650 ent = prev.initialize_entity_next;
1654 initialize_entity_first = ent.initialize_entity_next;
1655 ent = initialize_entity_first;
1661 ent = ent.initialize_entity_next;
1667 void objerror(string s)
1669 make_safe_for_remove(self);
1670 objerror_builtin(s);
1673 void remove_unsafely(entity e)
1678 void remove_safely(entity e)
1680 make_safe_for_remove(e);
1684 void InitializeEntity(entity e, void(void) func, float order)
1688 if (!e || e.initialize_entity)
1690 // make a proxy initializer entity
1694 e.classname = "initialize_entity";
1698 e.initialize_entity = func;
1699 e.initialize_entity_order = order;
1701 cur = initialize_entity_first;
1704 if (!cur || cur.initialize_entity_order > order)
1706 // insert between prev and cur
1708 prev.initialize_entity_next = e;
1710 initialize_entity_first = e;
1711 e.initialize_entity_next = cur;
1715 cur = cur.initialize_entity_next;
1718 void InitializeEntitiesRun()
1721 startoflist = initialize_entity_first;
1722 initialize_entity_first = world;
1723 for (self = startoflist; self; )
1726 var void(void) func;
1727 e = self.initialize_entity_next;
1728 func = self.initialize_entity;
1729 self.initialize_entity_order = 0;
1730 self.initialize_entity = func_null;
1731 self.initialize_entity_next = world;
1732 if (self.classname == "initialize_entity")
1736 remove_builtin(self);
1739 //dprint("Delayed initialization: ", self.classname, "\n");
1745 .float uncustomizeentityforclient_set;
1746 .void(void) uncustomizeentityforclient;
1747 void(void) SUB_Nullpointer = #0;
1748 void UncustomizeEntitiesRun()
1752 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1753 self.uncustomizeentityforclient();
1756 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1758 e.customizeentityforclient = customizer;
1759 e.uncustomizeentityforclient = uncustomizer;
1760 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1764 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1767 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1771 if (e.classname == "")
1772 e.classname = "net_linked";
1774 if (e.model == "" || self.modelindex == 0)
1778 setmodel(e, "null");
1782 e.SendEntity = sendfunc;
1783 e.SendFlags = 0xFFFFFF;
1786 e.effects |= EF_NODEPTHTEST;
1790 e.nextthink = time + dt;
1791 e.think = SUB_Remove;
1795 void adaptor_think2touch()
1804 void adaptor_think2use()
1816 // deferred dropping
1817 void DropToFloor_Handler()
1819 droptofloor_builtin();
1820 self.dropped_origin = self.origin;
1825 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1830 float trace_hits_box_a0, trace_hits_box_a1;
1832 float trace_hits_box_1d(float end, float thmi, float thma)
1836 // just check if x is in range
1844 // do the trace with respect to x
1845 // 0 -> end has to stay in thmi -> thma
1846 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1847 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1848 if (trace_hits_box_a0 > trace_hits_box_a1)
1854 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1859 // now it is a trace from 0 to end
1861 trace_hits_box_a0 = 0;
1862 trace_hits_box_a1 = 1;
1864 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1866 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1868 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1874 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1876 return trace_hits_box(start, end, thmi - ma, thma - mi);
1879 float SUB_NoImpactCheck()
1881 // zero hitcontents = this is not the real impact, but either the
1882 // mirror-impact of something hitting the projectile instead of the
1883 // projectile hitting the something, or a touchareagrid one. Neither of
1884 // these stop the projectile from moving, so...
1885 if(trace_dphitcontents == 0)
1887 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1890 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1892 if (other == world && self.size != '0 0 0')
1895 tic = self.velocity * sys_ticrate;
1896 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1897 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1898 if (trace_fraction >= 1)
1900 dprint("Odd... did not hit...?\n");
1902 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1904 dprint("Detected and prevented the sky-grapple bug.\n");
1912 #define SUB_OwnerCheck() (other && (other == self.owner))
1914 #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)
1916 float MAX_IPBAN_URIS = 16;
1918 float URI_GET_DISCARD = 0;
1919 float URI_GET_IPBAN = 1;
1920 float URI_GET_IPBAN_END = 16;
1922 void URI_Get_Callback(float id, float status, string data)
1924 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
1926 dprint("\nEnd of data.\n");
1928 if (id == URI_GET_DISCARD)
1932 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1935 OnlineBanList_URI_Get_Callback(id, status, data);
1939 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1943 void print_to(entity e, string s)
1946 sprint(e, strcat(s, "\n"));
1965 for (i = 0; i < MapInfo_count; ++i)
1967 if (MapInfo_Get_ByID(i))
1969 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
1972 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
1973 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
1981 for (i = 0; i < MapInfo_count; ++i)
1983 if (MapInfo_Get_ByID(i))
1985 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/racerecord/time")));
1988 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/racerecord/netname"));
1989 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, mmsss(r)), " ", h, "\n");
1997 for (i = 0; i < MapInfo_count; ++i)
1999 if (MapInfo_Get_ByID(i))
2001 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/ctsrecord/time")));
2004 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/ctsrecord/netname"));
2005 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, mmsss(r)), " ", h, "\n");
2011 MapInfo_ClearTemps();
2014 return "No records are available on this server.\n";
2016 return strcat("Records on this server:\n", s);
2019 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2022 vector start, org, delta, end, enddown, mstart;
2024 m = e.dphitcontentsmask;
2025 e.dphitcontentsmask = goodcontents | badcontents;
2028 delta = world.maxs - world.mins;
2030 for (i = 0; i < attempts; ++i)
2032 start_x = org_x + random() * delta_x;
2033 start_y = org_y + random() * delta_y;
2034 start_z = org_z + random() * delta_z;
2036 // rule 1: start inside world bounds, and outside
2037 // solid, and don't start from somewhere where you can
2038 // fall down to evil
2039 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2040 if (trace_fraction >= 1)
2042 if (trace_startsolid)
2044 if (trace_dphitcontents & badcontents)
2046 if (trace_dphitq3surfaceflags & badsurfaceflags)
2049 // rule 2: if we are too high, lower the point
2050 if (trace_fraction * delta_z > maxaboveground)
2051 start = trace_endpos + '0 0 1' * maxaboveground;
2052 enddown = trace_endpos;
2054 // rule 3: make sure we aren't outside the map. This only works
2055 // for somewhat well formed maps. A good rule of thumb is that
2056 // the map should have a convex outside hull.
2057 // these can be traceLINES as we already verified the starting box
2058 mstart = start + 0.5 * (e.mins + e.maxs);
2059 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2060 if (trace_fraction >= 1)
2062 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2063 if (trace_fraction >= 1)
2065 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2066 if (trace_fraction >= 1)
2068 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2069 if (trace_fraction >= 1)
2071 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2072 if (trace_fraction >= 1)
2075 // find a random vector to "look at"
2076 end_x = org_x + random() * delta_x;
2077 end_y = org_y + random() * delta_y;
2078 end_z = org_z + random() * delta_z;
2079 end = start + normalize(end - start) * vlen(delta);
2081 // rule 4: start TO end must not be too short
2082 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2083 if (trace_startsolid)
2085 if (trace_fraction < minviewdistance / vlen(delta))
2088 // rule 5: don't want to look at sky
2089 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2092 // rule 6: we must not end up in trigger_hurt
2093 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2095 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2102 e.dphitcontentsmask = m;
2106 setorigin(e, start);
2107 e.angles = vectoangles(end - start);
2108 dprint("Needed ", ftos(i + 1), " attempts\n");
2115 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2117 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2118 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2119 WriteShort(MSG_BROADCAST, effectno);
2120 WriteCoord(MSG_BROADCAST, start_x);
2121 WriteCoord(MSG_BROADCAST, start_y);
2122 WriteCoord(MSG_BROADCAST, start_z);
2123 WriteCoord(MSG_BROADCAST, end_x);
2124 WriteCoord(MSG_BROADCAST, end_y);
2125 WriteCoord(MSG_BROADCAST, end_z);
2126 WriteCoord(MSG_BROADCAST, end_dz);
2127 WriteShort(MSG_BROADCAST, spd / 16);
2130 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2133 vector vecxy, velxy;
2135 vecxy = end - start;
2140 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2142 trailparticles(world, effectno, start, end);
2146 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2147 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2150 string GetGametype(); // g_world.qc
2151 void write_recordmarker(entity pl, float tstart, float dt)
2153 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2155 // also write a marker into demo files for demotc-race-record-extractor to find
2158 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", mmsss(dt * 10)),
2159 " ", ftos(tstart), " ", ftos(dt), "\n"));
2162 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2167 if (cvar("g_shootfromclient"))
2169 switch(self.owner.cvar_cl_gunalign)
2185 else if (cvar("g_shootfromeye"))
2198 else if (cvar("g_shootfromcenter"))
2203 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2218 void attach_sameorigin(entity e, entity to, string tag)
2220 vector org, t_forward, t_left, t_up, e_forward, e_up;
2227 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2228 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2229 t_forward = v_forward * tagscale;
2230 t_left = v_right * -tagscale;
2231 t_up = v_up * tagscale;
2233 e.origin_x = org * t_forward;
2234 e.origin_y = org * t_left;
2235 e.origin_z = org * t_up;
2237 // current forward and up directions
2238 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2239 e.angles_x = -e.angles_x;
2240 fixedmakevectors(e.angles);
2242 // untransform forward, up!
2243 e_forward_x = v_forward * t_forward;
2244 e_forward_y = v_forward * t_left;
2245 e_forward_z = v_forward * t_up;
2246 e_up_x = v_up * t_forward;
2247 e_up_y = v_up * t_left;
2248 e_up_z = v_up * t_up;
2250 e.angles = fixedvectoangles2(e_forward, e_up);
2251 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2252 e.angles_x = -e.angles_x;
2254 setattachment(e, to, tag);
2255 setorigin(e, e.origin);
2258 void detach_sameorigin(entity e)
2261 org = gettaginfo(e, 0);
2262 e.angles = fixedvectoangles2(v_forward, v_up);
2263 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2264 e.angles_x = -e.angles_x;
2266 setattachment(e, world, "");
2267 setorigin(e, e.origin);
2270 void follow_sameorigin(entity e, entity to)
2272 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2273 e.aiment = to; // make the hole follow bmodel
2274 e.punchangle = to.angles; // the original angles of bmodel
2275 e.view_ofs = e.origin - to.origin; // relative origin
2276 e.v_angle = e.angles - to.angles; // relative angles
2279 void unfollow_sameorigin(entity e)
2281 e.movetype = MOVETYPE_NONE;
2284 entity gettaginfo_relative_ent;
2285 vector gettaginfo_relative(entity e, float tag)
2287 if (!gettaginfo_relative_ent)
2289 gettaginfo_relative_ent = spawn();
2290 gettaginfo_relative_ent.effects = EF_NODRAW;
2292 gettaginfo_relative_ent.model = e.model;
2293 gettaginfo_relative_ent.modelindex = e.modelindex;
2294 gettaginfo_relative_ent.frame = e.frame;
2295 return gettaginfo(gettaginfo_relative_ent, tag);
2298 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2302 if (pl.soundentity.cnt & p)
2304 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2305 pl.soundentity.cnt |= p;
2308 void SoundEntity_StopSound(entity pl, float chan)
2312 if (pl.soundentity.cnt & p)
2314 stopsoundto(MSG_ALL, pl.soundentity, chan);
2315 pl.soundentity.cnt &~= p;
2319 void SoundEntity_Attach(entity pl)
2321 pl.soundentity = spawn();
2322 pl.soundentity.classname = "soundentity";
2323 pl.soundentity.owner = pl;
2324 setattachment(pl.soundentity, pl, "");
2325 setmodel(pl.soundentity, "null");
2328 void SoundEntity_Detach(entity pl)
2331 for (i = 0; i <= 7; ++i)
2332 SoundEntity_StopSound(pl, i);
2336 float ParseCommandPlayerSlotTarget_firsttoken;
2337 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2345 ParseCommandPlayerSlotTarget_firsttoken = -1;
2349 if (substring(argv(idx), 0, 1) == "#")
2351 s = substring(argv(idx), 1, -1);
2359 if (s == ftos(stof(s)))
2361 e = edict_num(stof(s));
2362 if (e.flags & FL_CLIENT)
2364 ParseCommandPlayerSlotTarget_firsttoken = idx;
2371 // it must be a nick name
2376 FOR_EACH_CLIENT(head)
2377 if (head.netname == s)
2384 ParseCommandPlayerSlotTarget_firsttoken = idx;
2388 s = strdecolorize(s);
2390 FOR_EACH_CLIENT(head)
2391 if (strdecolorize(head.netname) == s)
2398 ParseCommandPlayerSlotTarget_firsttoken = idx;