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 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
536 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
537 GetCvars_handleFloat(s, f, cvar_cl_gunalign, "cl_gunalign");
540 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
543 if (s == "cl_weaponpriority")
544 self.switchweapon = w_getbestweapon(self);
548 float fexists(string f)
551 fh = fopen(f, FILE_READ);
558 void backtrace(string msg)
561 dev = cvar("developer");
562 cvar_set("developer", "1");
564 dprint("--- CUT HERE ---\nWARNING: ");
567 remove(world); // isn't there any better way to cause a backtrace?
568 dprint("\n--- CUT UNTIL HERE ---\n");
569 cvar_set("developer", ftos(dev));
572 string Team_ColorCode(float teamid)
574 if (teamid == COLOR_TEAM1)
576 else if (teamid == COLOR_TEAM2)
578 else if (teamid == COLOR_TEAM3)
580 else if (teamid == COLOR_TEAM4)
585 string Team_ColorName(float t)
587 // fixme: Search for team entities and get their .netname's!
588 if (t == COLOR_TEAM1)
590 if (t == COLOR_TEAM2)
592 if (t == COLOR_TEAM3)
594 if (t == COLOR_TEAM4)
598 string Team_ColorNameLowerCase(float t)
600 // fixme: Search for team entities and get their .netname's!
601 if (t == COLOR_TEAM1)
603 if (t == COLOR_TEAM2)
605 if (t == COLOR_TEAM3)
607 if (t == COLOR_TEAM4)
612 #define CENTERPRIO_POINT 1
613 #define CENTERPRIO_SPAM 2
614 #define CENTERPRIO_VOTE 4
615 #define CENTERPRIO_NORMAL 5
616 #define CENTERPRIO_SHIELDING 7
617 #define CENTERPRIO_MAPVOTE 9
618 #define CENTERPRIO_IDLEKICK 50
619 #define CENTERPRIO_ADMIN 99
620 .float centerprint_priority;
621 .float centerprint_expires;
622 void centerprint_atprio(entity e, float prio, string s)
624 if (intermission_running)
625 if (prio < CENTERPRIO_MAPVOTE)
627 if (time > e.centerprint_expires)
628 e.centerprint_priority = 0;
629 if (prio >= e.centerprint_priority)
631 e.centerprint_priority = prio;
632 if (timeoutStatus == 2)
633 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
635 e.centerprint_expires = time + e.cvar_scr_centertime;
636 centerprint_builtin(e, s);
639 void centerprint_expire(entity e, float prio)
641 if (prio == e.centerprint_priority)
643 e.centerprint_priority = 0;
644 centerprint_builtin(e, "");
647 void centerprint(entity e, string s)
649 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
652 // decolorizes and team colors the player name when needed
653 string playername(entity p)
656 if (teams_matter && !intermission_running && p.classname == "player")
658 t = Team_ColorCode(p.team);
659 return strcat(t, strdecolorize(p.netname));
665 vector randompos(vector m1, vector m2)
669 v_x = m2_x * random() + m1_x;
670 v_y = m2_y * random() + m1_y;
671 v_z = m2_z * random() + m1_z;
675 float g_pickup_shells;
676 float g_pickup_shells_max;
677 float g_pickup_nails;
678 float g_pickup_nails_max;
679 float g_pickup_rockets;
680 float g_pickup_rockets_max;
681 float g_pickup_cells;
682 float g_pickup_cells_max;
684 float g_pickup_fuel_jetpack;
685 float g_pickup_fuel_max;
686 float g_pickup_armorsmall;
687 float g_pickup_armorsmall_max;
688 float g_pickup_armormedium;
689 float g_pickup_armormedium_max;
690 float g_pickup_armorbig;
691 float g_pickup_armorbig_max;
692 float g_pickup_armorlarge;
693 float g_pickup_armorlarge_max;
694 float g_pickup_healthsmall;
695 float g_pickup_healthsmall_max;
696 float g_pickup_healthmedium;
697 float g_pickup_healthmedium_max;
698 float g_pickup_healthlarge;
699 float g_pickup_healthlarge_max;
700 float g_pickup_healthmega;
701 float g_pickup_healthmega_max;
703 string g_weaponarena_list;
704 float g_weaponspeedfactor;
705 float g_weapondamagefactor;
709 float start_ammo_shells;
710 float start_ammo_nails;
711 float start_ammo_rockets;
712 float start_ammo_cells;
713 float start_ammo_fuel;
715 float start_armorvalue;
716 float warmup_start_weapons;
717 float warmup_start_ammo_shells;
718 float warmup_start_ammo_nails;
719 float warmup_start_ammo_rockets;
720 float warmup_start_ammo_cells;
721 float warmup_start_ammo_fuel;
722 float warmup_start_health;
723 float warmup_start_armorvalue;
726 entity get_weaponinfo(float w);
728 float NixNex_CanChooseWeapon(float wpn);
729 void readplayerstartcvars()
735 // initialize starting values for players
738 start_ammo_shells = 0;
739 start_ammo_nails = 0;
740 start_ammo_rockets = 0;
741 start_ammo_cells = 0;
742 start_health = cvar("g_balance_health_start");
743 start_armorvalue = cvar("g_balance_armor_start");
746 s = cvar_string("g_weaponarena");
752 g_weaponarena_list = "All Weapons";
753 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
755 e = get_weaponinfo(j);
756 g_weaponarena |= e.weapons;
757 weapon_action(e.weapon, WR_PRECACHE);
760 else if (s == "most")
762 g_weaponarena_list = "Most Weapons";
763 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
765 e = get_weaponinfo(j);
766 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
768 g_weaponarena |= e.weapons;
769 weapon_action(e.weapon, WR_PRECACHE);
773 else if (s == "none")
775 g_weaponarena_list = "No Weapons";
776 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
780 t = tokenize_console(s);
781 g_weaponarena_list = "";
782 for (i = 0; i < t; ++i)
785 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
787 e = get_weaponinfo(j);
790 g_weaponarena |= e.weapons;
791 weapon_action(e.weapon, WR_PRECACHE);
792 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
798 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
801 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
807 // will be done later
808 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
809 if (NixNex_CanChooseWeapon(i))
810 weapon_action(i, WR_PRECACHE);
811 if(!cvar("g_use_ammunition"))
812 start_items |= IT_UNLIMITED_AMMO;
814 else if (g_weaponarena)
816 start_weapons = g_weaponarena;
817 start_ammo_rockets = 999;
818 start_ammo_shells = 999;
819 start_ammo_cells = 999;
820 start_ammo_nails = 999;
821 start_ammo_fuel = 999;
822 start_items |= IT_UNLIMITED_AMMO;
824 else if (g_minstagib)
827 start_armorvalue = 0;
828 start_weapons = WEPBIT_MINSTANEX;
829 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
830 start_ammo_cells = cvar("g_minstagib_ammo_start");
831 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
832 start_ammo_fuel = cvar("g_start_ammo_fuel");
834 if (g_minstagib_invis_alpha <= 0)
835 g_minstagib_invis_alpha = -1;
841 start_ammo_shells = cvar("g_lms_start_ammo_shells");
842 start_ammo_nails = cvar("g_lms_start_ammo_nails");
843 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
844 start_ammo_cells = cvar("g_lms_start_ammo_cells");
845 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
846 start_health = cvar("g_lms_start_health");
847 start_armorvalue = cvar("g_lms_start_armor");
849 else if (cvar("g_use_ammunition"))
851 start_ammo_shells = cvar("g_start_ammo_shells");
852 start_ammo_nails = cvar("g_start_ammo_nails");
853 start_ammo_rockets = cvar("g_start_ammo_rockets");
854 start_ammo_cells = cvar("g_start_ammo_cells");
855 start_ammo_fuel = cvar("g_start_ammo_fuel");
859 start_ammo_shells = cvar("g_pickup_shells_max");
860 start_ammo_nails = cvar("g_pickup_nails_max");
861 start_ammo_rockets = cvar("g_pickup_rockets_max");
862 start_ammo_cells = cvar("g_pickup_cells_max");
863 start_ammo_fuel = cvar("g_pickup_fuel_max");
864 start_items |= IT_UNLIMITED_AMMO;
867 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
869 e = get_weaponinfo(i);
873 t = cvar(strcat("g_start_weapon_", e.netname));
875 if (t < 0) // "default" weapon selection
878 t = (e.spawnflags & WEPSPAWNFLAG_NORMAL);
879 else if (g_race || g_cts)
880 t = (i == WEP_LASER);
882 t = 0; // weapon is set a few lines later
884 t = (i == WEP_LASER || i == WEP_SHOTGUN);
885 if (g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
886 t += (i == WEP_HOOK);
889 if (g_nexball && i == WEP_PORTO)
894 start_weapons |= e.weapons;
895 weapon_action(e.weapon, WR_PRECACHE);
902 warmup_start_ammo_shells = start_ammo_shells;
903 warmup_start_ammo_nails = start_ammo_nails;
904 warmup_start_ammo_rockets = start_ammo_rockets;
905 warmup_start_ammo_cells = start_ammo_cells;
906 warmup_start_health = start_health;
907 warmup_start_armorvalue = start_armorvalue;
908 warmup_start_weapons = start_weapons;
910 if (!g_weaponarena && !g_nixnex && !g_minstagib)
912 if (cvar("g_use_ammunition"))
914 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
915 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
916 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
917 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
919 warmup_start_health = cvar("g_warmup_start_health");
920 warmup_start_armorvalue = cvar("g_warmup_start_armor");
921 if (cvar("g_warmup_allguns"))
923 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
925 e = get_weaponinfo(i);
928 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
930 warmup_start_weapons |= e.weapons;
931 weapon_action(e.weapon, WR_PRECACHE);
938 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
940 g_grappling_hook = 0; // these two can't coexist, as they use the same button
941 start_items |= IT_FUEL_REGEN;
942 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
946 start_items |= IT_JETPACK;
948 if (g_weapon_stay == 2)
950 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
951 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
952 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
953 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
954 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
955 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
956 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
957 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
958 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
959 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
962 start_ammo_shells = max(0, start_ammo_shells);
963 start_ammo_nails = max(0, start_ammo_nails);
964 start_ammo_cells = max(0, start_ammo_cells);
965 start_ammo_rockets = max(0, start_ammo_rockets);
966 start_ammo_fuel = max(0, start_ammo_fuel);
968 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
969 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
970 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
971 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
972 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
976 float g_bugrigs_planar_movement;
977 float g_bugrigs_planar_movement_car_jumping;
978 float g_bugrigs_reverse_spinning;
979 float g_bugrigs_reverse_speeding;
980 float g_bugrigs_reverse_stopping;
981 float g_bugrigs_air_steering;
982 float g_bugrigs_angle_smoothing;
983 float g_bugrigs_friction_floor;
984 float g_bugrigs_friction_brake;
985 float g_bugrigs_friction_air;
986 float g_bugrigs_accel;
987 float g_bugrigs_speed_ref;
988 float g_bugrigs_speed_pow;
989 float g_bugrigs_steer;
991 float g_touchexplode;
992 float g_touchexplode_radius;
993 float g_touchexplode_damage;
994 float g_touchexplode_edgedamage;
995 float g_touchexplode_force;
997 void readlevelcvars(void)
999 g_bugrigs = cvar("g_bugrigs");
1000 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1001 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1002 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1003 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1004 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1005 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1006 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1007 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1008 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1009 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1010 g_bugrigs_accel = cvar("g_bugrigs_accel");
1011 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1012 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1013 g_bugrigs_steer = cvar("g_bugrigs_steer");
1015 g_touchexplode = cvar("g_touchexplode");
1016 g_touchexplode_radius = cvar("g_touchexplode_radius");
1017 g_touchexplode_damage = cvar("g_touchexplode_damage");
1018 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1019 g_touchexplode_force = cvar("g_touchexplode_force");
1021 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1022 sv_loddistance1 = cvar("sv_loddistance1");
1023 sv_loddistance2 = cvar("sv_loddistance2");
1024 if(sv_loddistance2 <= sv_loddistance1)
1025 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1026 sv_clones = cvar("sv_clones");
1027 sv_cheats = cvar("sv_cheats");
1028 sv_gentle = cvar("sv_gentle");
1029 sv_foginterval = cvar("sv_foginterval");
1030 g_cloaked = cvar("g_cloaked");
1031 g_jump_grunt = cvar("g_jump_grunt");
1032 g_footsteps = cvar("g_footsteps");
1033 g_grappling_hook = cvar("g_grappling_hook");
1034 g_jetpack = cvar("g_jetpack");
1035 g_laserguided_missile = cvar("g_laserguided_missile");
1036 g_midair = cvar("g_midair");
1037 g_minstagib = cvar("g_minstagib");
1038 g_nixnex = cvar("g_nixnex");
1039 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1040 g_norecoil = cvar("g_norecoil");
1041 g_vampire = cvar("g_vampire");
1042 g_bloodloss = cvar("g_bloodloss");
1043 sv_maxidle = cvar("sv_maxidle");
1044 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1045 sv_pogostick = cvar("sv_pogostick");
1046 sv_doublejump = cvar("sv_doublejump");
1047 g_ctf_reverse = cvar("g_ctf_reverse");
1049 inWarmupStage = cvar("g_warmup");
1050 g_warmup_limit = cvar("g_warmup_limit");
1051 g_warmup_allguns = cvar("g_warmup_allguns");
1052 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1054 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
1055 inWarmupStage = 0; // these modes cannot work together, sorry
1057 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1058 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1059 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1060 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1061 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1062 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1063 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1064 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1065 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1066 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1067 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1068 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1070 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1071 if (g_nixnex) g_weaponarena = 0;
1074 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1075 g_weapondamagefactor = cvar("g_weapondamagefactor");
1077 g_pickup_shells = cvar("g_pickup_shells");
1078 g_pickup_shells_max = cvar("g_pickup_shells_max");
1079 g_pickup_nails = cvar("g_pickup_nails");
1080 g_pickup_nails_max = cvar("g_pickup_nails_max");
1081 g_pickup_rockets = cvar("g_pickup_rockets");
1082 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1083 g_pickup_cells = cvar("g_pickup_cells");
1084 g_pickup_cells_max = cvar("g_pickup_cells_max");
1085 g_pickup_fuel = cvar("g_pickup_fuel");
1086 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1087 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1088 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1089 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1090 g_pickup_armormedium = cvar("g_pickup_armormedium");
1091 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1092 g_pickup_armorbig = cvar("g_pickup_armorbig");
1093 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1094 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1095 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1096 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1097 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1098 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1099 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1100 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1101 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1102 g_pickup_healthmega = cvar("g_pickup_healthmega");
1103 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1105 g_pinata = cvar("g_pinata");
1107 g_weapon_stay = cvar("g_weapon_stay");
1108 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1111 if not(inWarmupStage)
1112 game_starttime = cvar("g_start_delay");
1114 readplayerstartcvars();
1118 // TODO sound pack system
1121 string precache_sound_builtin (string s) = #19;
1122 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1123 string precache_sound(string s)
1125 return precache_sound_builtin(strcat(soundpack, s));
1127 void play2(entity e, string filename)
1129 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1131 void sound(entity e, float chan, string samp, float vol, float atten)
1133 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1138 string precache_sound (string s) = #19;
1139 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1140 float precache_sound_index (string s) = #19;
1142 #define SND_VOLUME 1
1143 #define SND_ATTENUATION 2
1144 #define SND_LARGEENTITY 8
1145 #define SND_LARGESOUND 16
1147 float sound_allowed(float dest, entity e)
1149 // sounds from world may always pass
1152 if (e.classname == "body")
1154 if (e.owner && e.owner != e)
1159 // sounds to self may always pass
1160 if (dest == MSG_ONE)
1161 if (e == msg_entity)
1163 // sounds by players can be removed
1164 if (cvar("bot_sound_monopoly"))
1165 if (clienttype(e) == CLIENTTYPE_REAL)
1167 // anything else may pass
1171 void sound(entity e, float chan, string samp, float vol, float atten)
1173 if (!sound_allowed(MSG_BROADCAST, e))
1175 sound_builtin(e, chan, samp, vol, atten);
1177 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1181 if (!sound_allowed(dest, e))
1184 entno = num_for_edict(e);
1185 idx = precache_sound_index(samp);
1190 atten = floor(atten * 64);
1191 vol = floor(vol * 255);
1194 sflags |= SND_VOLUME;
1196 sflags |= SND_ATTENUATION;
1198 sflags |= SND_LARGEENTITY;
1200 sflags |= SND_LARGESOUND;
1202 WriteByte(dest, SVC_SOUND);
1203 WriteByte(dest, sflags);
1204 if (sflags & SND_VOLUME)
1205 WriteByte(dest, vol);
1206 if (sflags & SND_ATTENUATION)
1207 WriteByte(dest, atten);
1208 if (sflags & SND_LARGEENTITY)
1210 WriteShort(dest, entno);
1211 WriteByte(dest, chan);
1215 WriteShort(dest, entno * 8 + chan);
1217 if (sflags & SND_LARGESOUND)
1218 WriteShort(dest, idx);
1220 WriteByte(dest, idx);
1222 WriteCoord(dest, o_x);
1223 WriteCoord(dest, o_y);
1224 WriteCoord(dest, o_z);
1226 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1230 if (!sound_allowed(dest, e))
1233 o = e.origin + 0.5 * (e.mins + e.maxs);
1234 soundtoat(dest, e, o, chan, samp, vol, atten);
1236 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1238 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1240 void stopsoundto(float dest, entity e, float chan)
1244 if (!sound_allowed(dest, e))
1247 entno = num_for_edict(e);
1252 idx = precache_sound_index("misc/null.wav");
1253 sflags = SND_LARGEENTITY;
1255 sflags |= SND_LARGESOUND;
1256 WriteByte(dest, SVC_SOUND);
1257 WriteByte(dest, sflags);
1258 WriteShort(dest, entno);
1259 WriteByte(dest, chan);
1260 if (sflags & SND_LARGESOUND)
1261 WriteShort(dest, idx);
1263 WriteByte(dest, idx);
1264 WriteCoord(dest, e.origin_x);
1265 WriteCoord(dest, e.origin_y);
1266 WriteCoord(dest, e.origin_z);
1270 WriteByte(dest, SVC_STOPSOUND);
1271 WriteShort(dest, entno * 8 + chan);
1274 void stopsound(entity e, float chan)
1276 if (!sound_allowed(MSG_BROADCAST, e))
1279 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1280 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1283 void play2(entity e, string filename)
1285 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1287 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1290 .float announcetime;
1291 float announce(entity player, string msg)
1293 if (time > player.announcetime)
1294 if (clienttype(player) == CLIENTTYPE_REAL)
1296 player.announcetime = time + 0.8;
1302 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1303 float spamsound(entity e, float chan, string samp, float vol, float atten)
1305 if (!sound_allowed(MSG_BROADCAST, e))
1308 if (time > e.announcetime)
1310 e.announcetime = time;
1311 sound(e, chan, samp, vol, atten);
1317 void play2team(float t, string filename)
1321 if (cvar("bot_sound_monopoly"))
1324 FOR_EACH_REALPLAYER(head)
1327 play2(head, filename);
1331 void play2all(string samp)
1333 if (cvar("bot_sound_monopoly"))
1336 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1339 void PrecachePlayerSounds(string f);
1340 void precache_all_models(string pattern)
1342 float globhandle, i, n;
1345 globhandle = search_begin(pattern, TRUE, FALSE);
1348 n = search_getsize(globhandle);
1349 for (i = 0; i < n; ++i)
1351 //print(search_getfilename(globhandle, i), "\n");
1352 f = search_getfilename(globhandle, i);
1355 if(substring(f, -9,5) == "_lod1")
1357 if(substring(f, -9,5) == "_lod2")
1359 if(!sv_loddistance1)
1361 PrecachePlayerSounds(strcat(f, ".sounds"));
1363 search_end(globhandle);
1368 // gamemode related things
1369 precache_model ("models/misc/chatbubble.spr");
1370 precache_model ("models/misc/teambubble.spr");
1373 precache_model ("models/runematch/curse.mdl");
1374 precache_model ("models/runematch/rune.mdl");
1377 #ifdef TTURRETS_ENABLED
1378 if (cvar("g_turrets"))
1382 // Precache all player models if desired
1383 if (cvar("sv_precacheplayermodels"))
1385 PrecachePlayerSounds("sound/player/default.sounds");
1386 precache_all_models("models/player/*.zym");
1387 precache_all_models("models/player/*.dpm");
1388 precache_all_models("models/player/*.md3");
1389 precache_all_models("models/player/*.psk");
1390 //precache_model("models/player/carni.zym");
1391 //precache_model("models/player/crash.zym");
1392 //precache_model("models/player/grunt.zym");
1393 //precache_model("models/player/headhunter.zym");
1394 //precache_model("models/player/insurrectionist.zym");
1395 //precache_model("models/player/jeandarc.zym");
1396 //precache_model("models/player/lurk.zym");
1397 //precache_model("models/player/lycanthrope.zym");
1398 //precache_model("models/player/marine.zym");
1399 //precache_model("models/player/nexus.zym");
1400 //precache_model("models/player/pyria.zym");
1401 //precache_model("models/player/shock.zym");
1402 //precache_model("models/player/skadi.zym");
1403 //precache_model("models/player/specop.zym");
1404 //precache_model("models/player/visitant.zym");
1407 if (cvar("sv_defaultcharacter"))
1410 s = cvar_string("sv_defaultplayermodel_red");
1414 PrecachePlayerSounds(strcat(s, ".sounds"));
1416 s = cvar_string("sv_defaultplayermodel_blue");
1420 PrecachePlayerSounds(strcat(s, ".sounds"));
1422 s = cvar_string("sv_defaultplayermodel_yellow");
1426 PrecachePlayerSounds(strcat(s, ".sounds"));
1428 s = cvar_string("sv_defaultplayermodel_pink");
1432 PrecachePlayerSounds(strcat(s, ".sounds"));
1434 s = cvar_string("sv_defaultplayermodel");
1438 PrecachePlayerSounds(strcat(s, ".sounds"));
1444 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1445 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1448 // gore and miscellaneous sounds
1449 //precache_sound ("misc/h2ohit.wav");
1450 precache_model ("models/hook.md3");
1451 precache_sound ("misc/armorimpact.wav");
1452 precache_sound ("misc/bodyimpact1.wav");
1453 precache_sound ("misc/bodyimpact2.wav");
1454 precache_sound ("misc/gib.wav");
1455 precache_sound ("misc/gib_splat01.wav");
1456 precache_sound ("misc/gib_splat02.wav");
1457 precache_sound ("misc/gib_splat03.wav");
1458 precache_sound ("misc/gib_splat04.wav");
1459 precache_sound ("misc/hit.wav");
1460 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1461 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1462 precache_sound ("misc/null.wav");
1463 precache_sound ("misc/spawn.wav");
1464 precache_sound ("misc/talk.wav");
1465 precache_sound ("misc/teleport.wav");
1466 precache_sound ("misc/poweroff.wav");
1467 precache_sound ("player/lava.wav");
1468 precache_sound ("player/slime.wav");
1471 precache_sound ("misc/jetpack_fly.wav");
1473 // announcer sounds - male
1474 precache_sound ("announcer/male/electrobitch.wav");
1475 precache_sound ("announcer/male/airshot.wav");
1476 precache_sound ("announcer/male/03kills.wav");
1477 precache_sound ("announcer/male/05kills.wav");
1478 precache_sound ("announcer/male/10kills.wav");
1479 precache_sound ("announcer/male/15kills.wav");
1480 precache_sound ("announcer/male/20kills.wav");
1481 precache_sound ("announcer/male/25kills.wav");
1482 precache_sound ("announcer/male/30kills.wav");
1483 precache_sound ("announcer/male/botlike.wav");
1484 precache_sound ("announcer/male/yoda.wav");
1485 precache_sound ("announcer/male/amazing.wav");
1486 precache_sound ("announcer/male/awesome.wav");
1487 precache_sound ("announcer/male/headshot.wav");
1488 precache_sound ("announcer/male/impressive.wav");
1490 // announcer sounds - robotic
1491 precache_sound ("announcer/robotic/prepareforbattle.wav");
1492 precache_sound ("announcer/robotic/begin.wav");
1493 precache_sound ("announcer/robotic/timeoutcalled.wav");
1494 precache_sound ("announcer/robotic/1fragleft.wav");
1495 precache_sound ("announcer/robotic/2fragsleft.wav");
1496 precache_sound ("announcer/robotic/3fragsleft.wav");
1499 precache_sound ("announcer/robotic/lastsecond.wav");
1500 precache_sound ("announcer/robotic/narrowly.wav");
1503 precache_model ("models/sprites/1.spr32");
1504 precache_model ("models/sprites/2.spr32");
1505 precache_model ("models/sprites/3.spr32");
1506 precache_model ("models/sprites/4.spr32");
1507 precache_model ("models/sprites/5.spr32");
1508 precache_model ("models/sprites/6.spr32");
1509 precache_model ("models/sprites/7.spr32");
1510 precache_model ("models/sprites/8.spr32");
1511 precache_model ("models/sprites/9.spr32");
1512 precache_model ("models/sprites/10.spr32");
1513 precache_sound ("announcer/robotic/1.wav");
1514 precache_sound ("announcer/robotic/2.wav");
1515 precache_sound ("announcer/robotic/3.wav");
1516 precache_sound ("announcer/robotic/4.wav");
1517 precache_sound ("announcer/robotic/5.wav");
1518 precache_sound ("announcer/robotic/6.wav");
1519 precache_sound ("announcer/robotic/7.wav");
1520 precache_sound ("announcer/robotic/8.wav");
1521 precache_sound ("announcer/robotic/9.wav");
1522 precache_sound ("announcer/robotic/10.wav");
1524 // common weapon precaches
1525 precache_sound ("weapons/weapon_switch.wav");
1526 precache_sound ("weapons/weaponpickup.wav");
1527 precache_sound ("weapons/unavailable.wav");
1528 if (g_grappling_hook)
1530 precache_sound ("weapons/hook_fire.wav"); // hook
1531 precache_sound ("weapons/hook_impact.wav"); // hook
1534 if (cvar("sv_precacheweapons") || g_nixnex)
1536 //precache weapon models/sounds
1539 while (wep <= WEP_LAST)
1541 weapon_action(wep, WR_PRECACHE);
1546 precache_model("models/elaser.mdl");
1547 precache_model("models/laser.mdl");
1548 precache_model("models/ebomb.mdl");
1551 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1553 if (!self.noise && self.music) // quake 3 uses the music field
1554 self.noise = self.music;
1556 // plays music for the level if there is any
1559 precache_sound (self.noise);
1560 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1565 // sorry, but using \ in macros breaks line numbers
1566 #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
1567 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1568 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1570 vector ExactTriggerHit_mins;
1571 vector ExactTriggerHit_maxs;
1572 float ExactTriggerHit_Recurse()
1578 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1581 if (trace_ent == self)
1586 se.solid = SOLID_NOT;
1587 f = ExactTriggerHit_Recurse();
1593 float ExactTriggerHit()
1597 if not(self.modelindex)
1601 self.solid = SOLID_BSP;
1602 ExactTriggerHit_mins = other.absmin;
1603 ExactTriggerHit_maxs = other.absmax;
1604 f = ExactTriggerHit_Recurse();
1610 // WARNING: this kills the trace globals
1611 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1612 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1614 #define INITPRIO_FIRST 0
1615 #define INITPRIO_GAMETYPE 0
1616 #define INITPRIO_GAMETYPE_FALLBACK 1
1617 #define INITPRIO_CVARS 5
1618 #define INITPRIO_FINDTARGET 10
1619 #define INITPRIO_DROPTOFLOOR 20
1620 #define INITPRIO_SETLOCATION 90
1621 #define INITPRIO_LINKDOORS 91
1622 #define INITPRIO_LAST 99
1624 .void(void) initialize_entity;
1625 .float initialize_entity_order;
1626 .entity initialize_entity_next;
1627 entity initialize_entity_first;
1629 void make_safe_for_remove(entity e)
1631 if (e.initialize_entity)
1634 for (ent = initialize_entity_first; ent; )
1636 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1638 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1639 // skip it in linked list
1642 prev.initialize_entity_next = ent.initialize_entity_next;
1643 ent = prev.initialize_entity_next;
1647 initialize_entity_first = ent.initialize_entity_next;
1648 ent = initialize_entity_first;
1654 ent = ent.initialize_entity_next;
1660 void objerror(string s)
1662 make_safe_for_remove(self);
1663 objerror_builtin(s);
1666 void remove_unsafely(entity e)
1671 void remove_safely(entity e)
1673 make_safe_for_remove(e);
1677 void InitializeEntity(entity e, void(void) func, float order)
1681 if (!e || e.initialize_entity)
1683 // make a proxy initializer entity
1687 e.classname = "initialize_entity";
1691 e.initialize_entity = func;
1692 e.initialize_entity_order = order;
1694 cur = initialize_entity_first;
1697 if (!cur || cur.initialize_entity_order > order)
1699 // insert between prev and cur
1701 prev.initialize_entity_next = e;
1703 initialize_entity_first = e;
1704 e.initialize_entity_next = cur;
1708 cur = cur.initialize_entity_next;
1711 void InitializeEntitiesRun()
1714 startoflist = initialize_entity_first;
1715 initialize_entity_first = world;
1716 for (self = startoflist; self; )
1719 var void(void) func;
1720 e = self.initialize_entity_next;
1721 func = self.initialize_entity;
1722 self.initialize_entity_order = 0;
1723 self.initialize_entity = func_null;
1724 self.initialize_entity_next = world;
1725 if (self.classname == "initialize_entity")
1729 remove_builtin(self);
1732 //dprint("Delayed initialization: ", self.classname, "\n");
1738 .float uncustomizeentityforclient_set;
1739 .void(void) uncustomizeentityforclient;
1740 void(void) SUB_Nullpointer = #0;
1741 void UncustomizeEntitiesRun()
1745 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1746 self.uncustomizeentityforclient();
1749 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1751 e.customizeentityforclient = customizer;
1752 e.uncustomizeentityforclient = uncustomizer;
1753 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1757 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1760 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1764 if (e.classname == "")
1765 e.classname = "net_linked";
1767 if (e.model == "" || self.modelindex == 0)
1771 setmodel(e, "null");
1775 e.SendEntity = sendfunc;
1776 e.SendFlags = 0xFFFFFF;
1779 e.effects |= EF_NODEPTHTEST;
1783 e.nextthink = time + dt;
1784 e.think = SUB_Remove;
1788 void adaptor_think2touch()
1797 void adaptor_think2use()
1809 // deferred dropping
1810 void DropToFloor_Handler()
1812 droptofloor_builtin();
1813 self.dropped_origin = self.origin;
1818 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1823 float trace_hits_box_a0, trace_hits_box_a1;
1825 float trace_hits_box_1d(float end, float thmi, float thma)
1829 // just check if x is in range
1837 // do the trace with respect to x
1838 // 0 -> end has to stay in thmi -> thma
1839 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1840 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1841 if (trace_hits_box_a0 > trace_hits_box_a1)
1847 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1852 // now it is a trace from 0 to end
1854 trace_hits_box_a0 = 0;
1855 trace_hits_box_a1 = 1;
1857 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1859 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1861 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1867 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1869 return trace_hits_box(start, end, thmi - ma, thma - mi);
1872 float SUB_NoImpactCheck()
1874 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1876 if (other == world && self.size != '0 0 0')
1879 tic = self.velocity * sys_ticrate;
1880 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1881 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1882 if (trace_fraction >= 1)
1884 dprint("Odd... did not hit...?\n");
1886 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1888 dprint("Detected and prevented the sky-grapple bug.\n");
1896 #define SUB_OwnerCheck() (other && (other == self.owner))
1898 #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)
1900 float MAX_IPBAN_URIS = 16;
1902 float URI_GET_DISCARD = 0;
1903 float URI_GET_IPBAN = 1;
1904 float URI_GET_IPBAN_END = 16;
1906 void URI_Get_Callback(float id, float status, string data)
1908 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
1910 dprint("\nEnd of data.\n");
1912 if (id == URI_GET_DISCARD)
1916 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1919 OnlineBanList_URI_Get_Callback(id, status, data);
1923 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1927 void print_to(entity e, string s)
1930 sprint(e, strcat(s, "\n"));
1949 for (i = 0; i < MapInfo_count; ++i)
1951 if (MapInfo_Get_ByID(i))
1953 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
1956 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
1957 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
1963 if (g_race || g_cts)
1965 for (i = 0; i < MapInfo_count; ++i)
1967 if (MapInfo_Get_ByID(i))
1969 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/racerecord/time")));
1972 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/racerecord/netname"));
1973 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, mmsss(r)), " ", h, "\n");
1979 MapInfo_ClearTemps();
1982 return "No records are available on this server.\n";
1984 return strcat("Records on this server:\n", s);
1987 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
1990 vector start, org, delta, end, enddown, mstart;
1992 m = e.dphitcontentsmask;
1993 e.dphitcontentsmask = goodcontents | badcontents;
1996 delta = world.maxs - world.mins;
1998 for (i = 0; i < attempts; ++i)
2000 start_x = org_x + random() * delta_x;
2001 start_y = org_y + random() * delta_y;
2002 start_z = org_z + random() * delta_z;
2004 // rule 1: start inside world bounds, and outside
2005 // solid, and don't start from somewhere where you can
2006 // fall down to evil
2007 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2008 if (trace_fraction >= 1)
2010 if (trace_startsolid)
2012 if (trace_dphitcontents & badcontents)
2014 if (trace_dphitq3surfaceflags & badsurfaceflags)
2017 // rule 2: if we are too high, lower the point
2018 if (trace_fraction * delta_z > maxaboveground)
2019 start = trace_endpos + '0 0 1' * maxaboveground;
2020 enddown = trace_endpos;
2022 // rule 3: make sure we aren't outside the map. This only works
2023 // for somewhat well formed maps. A good rule of thumb is that
2024 // the map should have a convex outside hull.
2025 // these can be traceLINES as we already verified the starting box
2026 mstart = start + 0.5 * (e.mins + e.maxs);
2027 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2028 if (trace_fraction >= 1)
2030 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2031 if (trace_fraction >= 1)
2033 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2034 if (trace_fraction >= 1)
2036 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2037 if (trace_fraction >= 1)
2039 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2040 if (trace_fraction >= 1)
2043 // find a random vector to "look at"
2044 end_x = org_x + random() * delta_x;
2045 end_y = org_y + random() * delta_y;
2046 end_z = org_z + random() * delta_z;
2047 end = start + normalize(end - start) * vlen(delta);
2049 // rule 4: start TO end must not be too short
2050 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2051 if (trace_startsolid)
2053 if (trace_fraction < minviewdistance / vlen(delta))
2056 // rule 5: don't want to look at sky
2057 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2060 // rule 6: we must not end up in trigger_hurt
2061 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2063 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2070 e.dphitcontentsmask = m;
2074 setorigin(e, start);
2075 e.angles = vectoangles(end - start);
2076 dprint("Needed ", ftos(i + 1), " attempts\n");
2083 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2085 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2086 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2087 WriteShort(MSG_BROADCAST, effectno);
2088 WriteCoord(MSG_BROADCAST, start_x);
2089 WriteCoord(MSG_BROADCAST, start_y);
2090 WriteCoord(MSG_BROADCAST, start_z);
2091 WriteCoord(MSG_BROADCAST, end_x);
2092 WriteCoord(MSG_BROADCAST, end_y);
2093 WriteCoord(MSG_BROADCAST, end_z);
2094 WriteCoord(MSG_BROADCAST, end_dz);
2095 WriteShort(MSG_BROADCAST, spd / 16);
2098 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2101 vector vecxy, velxy;
2103 vecxy = end - start;
2108 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2110 trailparticles(world, effectno, start, end);
2114 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2115 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2118 string GetGametype(); // g_world.qc
2119 void write_recordmarker(entity pl, float tstart, float dt)
2121 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt / 10)));
2123 // also write a marker into demo files for demotc-race-record-extractor to find
2126 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", mmsss(dt * 10)),
2127 " ", ftos(tstart), " ", ftos(dt), "\n"));
2130 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2135 if (cvar("g_shootfromclient"))
2137 switch(self.owner.cvar_cl_gunalign)
2153 else if (cvar("g_shootfromeye"))
2166 else if (cvar("g_shootfromcenter"))
2171 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2186 void attach_sameorigin(entity e, entity to, string tag)
2188 vector org, t_forward, t_left, t_up, e_forward, e_up;
2195 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2196 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2197 t_forward = v_forward * tagscale;
2198 t_left = v_right * -tagscale;
2199 t_up = v_up * tagscale;
2201 e.origin_x = org * t_forward;
2202 e.origin_y = org * t_left;
2203 e.origin_z = org * t_up;
2205 // current forward and up directions
2206 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2207 e.angles_x = -e.angles_x;
2208 fixedmakevectors(e.angles);
2210 // untransform forward, up!
2211 e_forward_x = v_forward * t_forward;
2212 e_forward_y = v_forward * t_left;
2213 e_forward_z = v_forward * t_up;
2214 e_up_x = v_up * t_forward;
2215 e_up_y = v_up * t_left;
2216 e_up_z = v_up * t_up;
2218 e.angles = fixedvectoangles2(e_forward, e_up);
2219 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2220 e.angles_x = -e.angles_x;
2222 setattachment(e, to, tag);
2223 setorigin(e, e.origin);
2226 void detach_sameorigin(entity e)
2229 org = gettaginfo(e, 0);
2230 e.angles = fixedvectoangles2(v_forward, v_up);
2231 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2232 e.angles_x = -e.angles_x;
2234 setattachment(e, world, "");
2235 setorigin(e, e.origin);
2238 void follow_sameorigin(entity e, entity to)
2240 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2241 e.aiment = to; // make the hole follow bmodel
2242 e.punchangle = to.angles; // the original angles of bmodel
2243 e.view_ofs = e.origin - to.origin; // relative origin
2244 e.v_angle = e.angles - to.angles; // relative angles
2247 void unfollow_sameorigin(entity e)
2249 e.movetype = MOVETYPE_NONE;
2252 entity gettaginfo_relative_ent;
2253 vector gettaginfo_relative(entity e, float tag)
2255 if (!gettaginfo_relative_ent)
2257 gettaginfo_relative_ent = spawn();
2258 gettaginfo_relative_ent.effects = EF_NODRAW;
2260 gettaginfo_relative_ent.model = e.model;
2261 gettaginfo_relative_ent.modelindex = e.modelindex;
2262 gettaginfo_relative_ent.frame = e.frame;
2263 return gettaginfo(gettaginfo_relative_ent, tag);
2266 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2270 if (pl.soundentity.cnt & p)
2272 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2273 pl.soundentity.cnt |= p;
2276 void SoundEntity_StopSound(entity pl, float chan)
2280 if (pl.soundentity.cnt & p)
2282 stopsoundto(MSG_ALL, pl.soundentity, chan);
2283 pl.soundentity.cnt &~= p;
2287 void SoundEntity_Attach(entity pl)
2289 pl.soundentity = spawn();
2290 pl.soundentity.classname = "soundentity";
2291 pl.soundentity.owner = pl;
2292 setattachment(pl.soundentity, pl, "");
2293 setmodel(pl.soundentity, "null");
2296 void SoundEntity_Detach(entity pl)
2299 for (i = 0; i <= 7; ++i)
2300 SoundEntity_StopSound(pl, i);
2304 float ParseCommandPlayerSlotTarget_firsttoken;
2305 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2313 ParseCommandPlayerSlotTarget_firsttoken = -1;
2317 if (substring(argv(idx), 0, 1) == "#")
2319 s = substring(argv(idx), 1, -1);
2327 if (s == ftos(stof(s)))
2329 e = edict_num(stof(s));
2330 if (e.flags & FL_CLIENT)
2332 ParseCommandPlayerSlotTarget_firsttoken = idx;
2339 // it must be a nick name
2344 FOR_EACH_CLIENT(head)
2345 if (head.netname == s)
2352 ParseCommandPlayerSlotTarget_firsttoken = idx;
2356 s = strdecolorize(s);
2358 FOR_EACH_CLIENT(head)
2359 if (strdecolorize(head.netname) == s)
2366 ParseCommandPlayerSlotTarget_firsttoken = idx;