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 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
513 if (thisname == name)
517 self.field = stof(argv(f + 1));
526 stuffcmd(self, strcat("sendcvar ", name, "\n"));
529 string W_FixWeaponOrder_ForceComplete(string s);
530 string W_FixWeaponOrder_AllowIncomplete(string s);
531 float w_getbestweapon(entity e);
532 void GetCvars(float f)
536 s = strcat1(argv(f));
537 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
538 GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
539 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
540 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
541 GetCvars_handleString(s, f, cvar_g_nexuizversion, "g_nexuizversion");
542 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
543 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
544 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
545 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
546 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
547 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
548 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
549 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
550 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
551 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
552 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
553 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
554 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
555 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
556 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
557 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
558 #ifdef ALLOW_FORCEMODELS
559 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
560 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz");
562 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
565 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
568 if (s == "cl_weaponpriority")
569 self.switchweapon = w_getbestweapon(self);
573 float fexists(string f)
576 fh = fopen(f, FILE_READ);
583 void backtrace(string msg)
586 dev = cvar("developer");
587 cvar_set("developer", "1");
589 dprint("--- CUT HERE ---\nWARNING: ");
592 remove(world); // isn't there any better way to cause a backtrace?
593 dprint("\n--- CUT UNTIL HERE ---\n");
594 cvar_set("developer", ftos(dev));
597 string Team_ColorCode(float teamid)
599 if (teamid == COLOR_TEAM1)
601 else if (teamid == COLOR_TEAM2)
603 else if (teamid == COLOR_TEAM3)
605 else if (teamid == COLOR_TEAM4)
610 string Team_ColorName(float t)
612 // fixme: Search for team entities and get their .netname's!
613 if (t == COLOR_TEAM1)
615 if (t == COLOR_TEAM2)
617 if (t == COLOR_TEAM3)
619 if (t == COLOR_TEAM4)
623 string Team_ColorNameLowerCase(float t)
625 // fixme: Search for team entities and get their .netname's!
626 if (t == COLOR_TEAM1)
628 if (t == COLOR_TEAM2)
630 if (t == COLOR_TEAM3)
632 if (t == COLOR_TEAM4)
637 #define CENTERPRIO_POINT 1
638 #define CENTERPRIO_SPAM 2
639 #define CENTERPRIO_VOTE 4
640 #define CENTERPRIO_NORMAL 5
641 #define CENTERPRIO_SHIELDING 7
642 #define CENTERPRIO_MAPVOTE 9
643 #define CENTERPRIO_IDLEKICK 50
644 #define CENTERPRIO_ADMIN 99
645 .float centerprint_priority;
646 .float centerprint_expires;
647 void centerprint_atprio(entity e, float prio, string s)
649 if (intermission_running)
650 if (prio < CENTERPRIO_MAPVOTE)
652 if (time > e.centerprint_expires)
653 e.centerprint_priority = 0;
654 if (prio >= e.centerprint_priority)
656 e.centerprint_priority = prio;
657 if (timeoutStatus == 2)
658 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
660 e.centerprint_expires = time + e.cvar_scr_centertime;
661 centerprint_builtin(e, s);
664 void centerprint_expire(entity e, float prio)
666 if (prio == e.centerprint_priority)
668 e.centerprint_priority = 0;
669 centerprint_builtin(e, "");
672 void centerprint(entity e, string s)
674 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
677 // decolorizes and team colors the player name when needed
678 string playername(entity p)
681 if (teams_matter && !intermission_running && p.classname == "player")
683 t = Team_ColorCode(p.team);
684 return strcat(t, strdecolorize(p.netname));
690 vector randompos(vector m1, vector m2)
694 v_x = m2_x * random() + m1_x;
695 v_y = m2_y * random() + m1_y;
696 v_z = m2_z * random() + m1_z;
700 float g_pickup_shells;
701 float g_pickup_shells_max;
702 float g_pickup_nails;
703 float g_pickup_nails_max;
704 float g_pickup_rockets;
705 float g_pickup_rockets_max;
706 float g_pickup_cells;
707 float g_pickup_cells_max;
709 float g_pickup_fuel_jetpack;
710 float g_pickup_fuel_max;
711 float g_pickup_armorsmall;
712 float g_pickup_armorsmall_max;
713 float g_pickup_armormedium;
714 float g_pickup_armormedium_max;
715 float g_pickup_armorbig;
716 float g_pickup_armorbig_max;
717 float g_pickup_armorlarge;
718 float g_pickup_armorlarge_max;
719 float g_pickup_healthsmall;
720 float g_pickup_healthsmall_max;
721 float g_pickup_healthmedium;
722 float g_pickup_healthmedium_max;
723 float g_pickup_healthlarge;
724 float g_pickup_healthlarge_max;
725 float g_pickup_healthmega;
726 float g_pickup_healthmega_max;
728 string g_weaponarena_list;
729 float g_weaponspeedfactor;
730 float g_weaponratefactor;
731 float g_weapondamagefactor;
732 float g_weaponforcefactor;
736 float start_ammo_shells;
737 float start_ammo_nails;
738 float start_ammo_rockets;
739 float start_ammo_cells;
740 float start_ammo_fuel;
742 float start_armorvalue;
743 float warmup_start_weapons;
744 float warmup_start_ammo_shells;
745 float warmup_start_ammo_nails;
746 float warmup_start_ammo_rockets;
747 float warmup_start_ammo_cells;
748 float warmup_start_ammo_fuel;
749 float warmup_start_health;
750 float warmup_start_armorvalue;
753 entity get_weaponinfo(float w);
755 float NixNex_CanChooseWeapon(float wpn);
756 void readplayerstartcvars()
762 // initialize starting values for players
765 start_ammo_shells = 0;
766 start_ammo_nails = 0;
767 start_ammo_rockets = 0;
768 start_ammo_cells = 0;
769 start_health = cvar("g_balance_health_start");
770 start_armorvalue = cvar("g_balance_armor_start");
773 s = cvar_string("g_weaponarena");
779 g_weaponarena_list = "All Weapons";
780 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
782 e = get_weaponinfo(j);
783 g_weaponarena |= e.weapons;
784 weapon_action(e.weapon, WR_PRECACHE);
787 else if (s == "most")
789 g_weaponarena_list = "Most Weapons";
790 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
792 e = get_weaponinfo(j);
793 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
795 g_weaponarena |= e.weapons;
796 weapon_action(e.weapon, WR_PRECACHE);
800 else if (s == "none")
802 g_weaponarena_list = "No Weapons";
803 g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit!
807 t = tokenize_console(s);
808 g_weaponarena_list = "";
809 for (i = 0; i < t; ++i)
812 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
814 e = get_weaponinfo(j);
817 g_weaponarena |= e.weapons;
818 weapon_action(e.weapon, WR_PRECACHE);
819 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
825 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
828 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
834 // will be done later
835 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
836 if (NixNex_CanChooseWeapon(i))
837 weapon_action(i, WR_PRECACHE);
838 if(!cvar("g_use_ammunition"))
839 start_items |= IT_UNLIMITED_AMMO;
841 else if (g_weaponarena)
843 start_weapons = g_weaponarena;
844 if (g_weaponarena & (WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_ROCKET_LAUNCHER))
845 start_ammo_rockets = 999;
846 if (g_weaponarena & WEPBIT_SHOTGUN)
847 start_ammo_shells = 999;
848 if (g_weaponarena & (WEPBIT_ELECTRO | WEPBIT_CRYLINK | WEPBIT_NEX | WEPBIT_MINSTANEX | WEPBIT_HLAC | WEPBIT_HOOK))
849 start_ammo_cells = 999;
850 if (g_weaponarena & (WEPBIT_UZI | WEPBIT_CAMPINGRIFLE))
851 start_ammo_nails = 999;
852 if (g_weaponarena & WEPBIT_HOOK)
853 start_ammo_fuel = 999;
854 start_items |= IT_UNLIMITED_AMMO;
856 else if (g_minstagib)
859 start_armorvalue = 0;
860 start_weapons = WEPBIT_MINSTANEX;
861 weapon_action(WEP_MINSTANEX, WR_PRECACHE);
862 start_ammo_cells = cvar("g_minstagib_ammo_start");
863 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
864 start_ammo_fuel = cvar("g_start_ammo_fuel");
866 if (g_minstagib_invis_alpha <= 0)
867 g_minstagib_invis_alpha = -1;
873 start_ammo_shells = cvar("g_lms_start_ammo_shells");
874 start_ammo_nails = cvar("g_lms_start_ammo_nails");
875 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
876 start_ammo_cells = cvar("g_lms_start_ammo_cells");
877 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
878 start_health = cvar("g_lms_start_health");
879 start_armorvalue = cvar("g_lms_start_armor");
881 else if (cvar("g_use_ammunition"))
883 start_ammo_shells = cvar("g_start_ammo_shells");
884 start_ammo_nails = cvar("g_start_ammo_nails");
885 start_ammo_rockets = cvar("g_start_ammo_rockets");
886 start_ammo_cells = cvar("g_start_ammo_cells");
887 start_ammo_fuel = cvar("g_start_ammo_fuel");
891 start_ammo_shells = cvar("g_pickup_shells_max");
892 start_ammo_nails = cvar("g_pickup_nails_max");
893 start_ammo_rockets = cvar("g_pickup_rockets_max");
894 start_ammo_cells = cvar("g_pickup_cells_max");
895 start_ammo_fuel = cvar("g_pickup_fuel_max");
896 start_items |= IT_UNLIMITED_AMMO;
899 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
901 e = get_weaponinfo(i);
905 t = cvar(strcat("g_start_weapon_", e.netname));
907 if (t < 0) // "default" weapon selection
910 t = (e.spawnflags & WEPSPAWNFLAG_NORMAL);
911 else if (g_race || g_cts)
912 t = (i == WEP_LASER);
914 t = 0; // weapon is set a few lines later
916 t = (i == WEP_LASER || i == WEP_SHOTGUN);
917 if (g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
918 t += (i == WEP_HOOK);
921 if (g_nexball && i == WEP_PORTO)
926 start_weapons |= e.weapons;
927 weapon_action(e.weapon, WR_PRECACHE);
934 warmup_start_ammo_shells = start_ammo_shells;
935 warmup_start_ammo_nails = start_ammo_nails;
936 warmup_start_ammo_rockets = start_ammo_rockets;
937 warmup_start_ammo_cells = start_ammo_cells;
938 warmup_start_health = start_health;
939 warmup_start_armorvalue = start_armorvalue;
940 warmup_start_weapons = start_weapons;
942 if (!g_weaponarena && !g_nixnex && !g_minstagib)
944 if (cvar("g_use_ammunition"))
946 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
947 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
948 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
949 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
951 warmup_start_health = cvar("g_warmup_start_health");
952 warmup_start_armorvalue = cvar("g_warmup_start_armor");
953 if (cvar("g_warmup_allguns"))
955 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
957 e = get_weaponinfo(i);
960 if (e.spawnflags & WEPSPAWNFLAG_NORMAL)
962 warmup_start_weapons |= e.weapons;
963 weapon_action(e.weapon, WR_PRECACHE);
970 if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK)))
972 g_grappling_hook = 0; // these two can't coexist, as they use the same button
973 start_items |= IT_FUEL_REGEN;
974 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
978 start_items |= IT_JETPACK;
980 if (g_weapon_stay == 2)
982 if (!start_ammo_shells) start_ammo_shells = g_pickup_shells;
983 if (!start_ammo_nails) start_ammo_nails = g_pickup_nails;
984 if (!start_ammo_cells) start_ammo_cells = g_pickup_cells;
985 if (!start_ammo_rockets) start_ammo_rockets = g_pickup_rockets;
986 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
987 if (!warmup_start_ammo_shells) warmup_start_ammo_shells = g_pickup_shells;
988 if (!warmup_start_ammo_nails) warmup_start_ammo_nails = g_pickup_nails;
989 if (!warmup_start_ammo_cells) warmup_start_ammo_cells = g_pickup_cells;
990 if (!warmup_start_ammo_rockets) warmup_start_ammo_rockets = g_pickup_rockets;
991 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
994 start_ammo_shells = max(0, start_ammo_shells);
995 start_ammo_nails = max(0, start_ammo_nails);
996 start_ammo_cells = max(0, start_ammo_cells);
997 start_ammo_rockets = max(0, start_ammo_rockets);
998 start_ammo_fuel = max(0, start_ammo_fuel);
1000 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
1001 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1002 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1003 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1004 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1008 float g_bugrigs_planar_movement;
1009 float g_bugrigs_planar_movement_car_jumping;
1010 float g_bugrigs_reverse_spinning;
1011 float g_bugrigs_reverse_speeding;
1012 float g_bugrigs_reverse_stopping;
1013 float g_bugrigs_air_steering;
1014 float g_bugrigs_angle_smoothing;
1015 float g_bugrigs_friction_floor;
1016 float g_bugrigs_friction_brake;
1017 float g_bugrigs_friction_air;
1018 float g_bugrigs_accel;
1019 float g_bugrigs_speed_ref;
1020 float g_bugrigs_speed_pow;
1021 float g_bugrigs_steer;
1023 float g_touchexplode;
1024 float g_touchexplode_radius;
1025 float g_touchexplode_damage;
1026 float g_touchexplode_edgedamage;
1027 float g_touchexplode_force;
1029 void readlevelcvars(void)
1031 g_bugrigs = cvar("g_bugrigs");
1032 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1033 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1034 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1035 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1036 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1037 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1038 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1039 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1040 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1041 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1042 g_bugrigs_accel = cvar("g_bugrigs_accel");
1043 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1044 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1045 g_bugrigs_steer = cvar("g_bugrigs_steer");
1047 g_touchexplode = cvar("g_touchexplode");
1048 g_touchexplode_radius = cvar("g_touchexplode_radius");
1049 g_touchexplode_damage = cvar("g_touchexplode_damage");
1050 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1051 g_touchexplode_force = cvar("g_touchexplode_force");
1053 #ifdef ALLOW_FORCEMODELS
1054 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1056 sv_loddistance1 = cvar("sv_loddistance1");
1057 sv_loddistance2 = cvar("sv_loddistance2");
1058 if(sv_loddistance2 <= sv_loddistance1)
1059 sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably
1060 sv_clones = cvar("sv_clones");
1061 sv_cheats = cvar("sv_cheats");
1062 sv_gentle = cvar("sv_gentle");
1063 sv_foginterval = cvar("sv_foginterval");
1064 g_cloaked = cvar("g_cloaked");
1065 g_jump_grunt = cvar("g_jump_grunt");
1066 g_footsteps = cvar("g_footsteps");
1067 g_grappling_hook = cvar("g_grappling_hook");
1068 g_jetpack = cvar("g_jetpack");
1069 g_laserguided_missile = cvar("g_laserguided_missile");
1070 g_midair = cvar("g_midair");
1071 g_minstagib = cvar("g_minstagib");
1072 g_nixnex = cvar("g_nixnex");
1073 g_nixnex_with_laser = cvar("g_nixnex_with_laser");
1074 g_norecoil = cvar("g_norecoil");
1075 g_vampire = cvar("g_vampire");
1076 g_bloodloss = cvar("g_bloodloss");
1077 sv_maxidle = cvar("sv_maxidle");
1078 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1079 sv_pogostick = cvar("sv_pogostick");
1080 sv_doublejump = cvar("sv_doublejump");
1081 g_ctf_reverse = cvar("g_ctf_reverse");
1083 inWarmupStage = cvar("g_warmup");
1084 g_warmup_limit = cvar("g_warmup_limit");
1085 g_warmup_allguns = cvar("g_warmup_allguns");
1086 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1088 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
1089 inWarmupStage = 0; // these modes cannot work together, sorry
1091 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1092 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1093 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1094 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1095 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1096 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1097 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1098 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1099 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1100 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1101 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1102 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1104 if (g_minstagib) g_nixnex = g_weaponarena = 0;
1105 if (g_nixnex) g_weaponarena = 0;
1108 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1109 g_weaponratefactor = cvar("g_weaponratefactor");
1110 g_weapondamagefactor = cvar("g_weapondamagefactor");
1111 g_weaponforcefactor = cvar("g_weaponforcefactor");
1113 g_pickup_shells = cvar("g_pickup_shells");
1114 g_pickup_shells_max = cvar("g_pickup_shells_max");
1115 g_pickup_nails = cvar("g_pickup_nails");
1116 g_pickup_nails_max = cvar("g_pickup_nails_max");
1117 g_pickup_rockets = cvar("g_pickup_rockets");
1118 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1119 g_pickup_cells = cvar("g_pickup_cells");
1120 g_pickup_cells_max = cvar("g_pickup_cells_max");
1121 g_pickup_fuel = cvar("g_pickup_fuel");
1122 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1123 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1124 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1125 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1126 g_pickup_armormedium = cvar("g_pickup_armormedium");
1127 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1128 g_pickup_armorbig = cvar("g_pickup_armorbig");
1129 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1130 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1131 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1132 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1133 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1134 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1135 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1136 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1137 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1138 g_pickup_healthmega = cvar("g_pickup_healthmega");
1139 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1141 g_pinata = cvar("g_pinata");
1143 g_weapon_stay = cvar("g_weapon_stay");
1144 if (!g_weapon_stay && (cvar("deathmatch") == 2))
1147 if not(inWarmupStage)
1148 game_starttime = cvar("g_start_delay");
1150 readplayerstartcvars();
1154 // TODO sound pack system
1157 string precache_sound_builtin (string s) = #19;
1158 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1159 string precache_sound(string s)
1161 return precache_sound_builtin(strcat(soundpack, s));
1163 void play2(entity e, string filename)
1165 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
1167 void sound(entity e, float chan, string samp, float vol, float atten)
1169 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
1174 string precache_sound (string s) = #19;
1175 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
1176 float precache_sound_index (string s) = #19;
1178 #define SND_VOLUME 1
1179 #define SND_ATTENUATION 2
1180 #define SND_LARGEENTITY 8
1181 #define SND_LARGESOUND 16
1183 float sound_allowed(float dest, entity e)
1185 // sounds from world may always pass
1188 if (e.classname == "body")
1190 if (e.owner && e.owner != e)
1195 // sounds to self may always pass
1196 if (dest == MSG_ONE)
1197 if (e == msg_entity)
1199 // sounds by players can be removed
1200 if (cvar("bot_sound_monopoly"))
1201 if (clienttype(e) == CLIENTTYPE_REAL)
1203 // anything else may pass
1207 void sound(entity e, float chan, string samp, float vol, float atten)
1209 if (!sound_allowed(MSG_BROADCAST, e))
1211 sound_builtin(e, chan, samp, vol, atten);
1213 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1217 if (!sound_allowed(dest, e))
1220 entno = num_for_edict(e);
1221 idx = precache_sound_index(samp);
1226 atten = floor(atten * 64);
1227 vol = floor(vol * 255);
1230 sflags |= SND_VOLUME;
1232 sflags |= SND_ATTENUATION;
1234 sflags |= SND_LARGEENTITY;
1236 sflags |= SND_LARGESOUND;
1238 WriteByte(dest, SVC_SOUND);
1239 WriteByte(dest, sflags);
1240 if (sflags & SND_VOLUME)
1241 WriteByte(dest, vol);
1242 if (sflags & SND_ATTENUATION)
1243 WriteByte(dest, atten);
1244 if (sflags & SND_LARGEENTITY)
1246 WriteShort(dest, entno);
1247 WriteByte(dest, chan);
1251 WriteShort(dest, entno * 8 + chan);
1253 if (sflags & SND_LARGESOUND)
1254 WriteShort(dest, idx);
1256 WriteByte(dest, idx);
1258 WriteCoord(dest, o_x);
1259 WriteCoord(dest, o_y);
1260 WriteCoord(dest, o_z);
1262 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1266 if (!sound_allowed(dest, e))
1269 o = e.origin + 0.5 * (e.mins + e.maxs);
1270 soundtoat(dest, e, o, chan, samp, vol, atten);
1272 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1274 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
1276 void stopsoundto(float dest, entity e, float chan)
1280 if (!sound_allowed(dest, e))
1283 entno = num_for_edict(e);
1288 idx = precache_sound_index("misc/null.wav");
1289 sflags = SND_LARGEENTITY;
1291 sflags |= SND_LARGESOUND;
1292 WriteByte(dest, SVC_SOUND);
1293 WriteByte(dest, sflags);
1294 WriteShort(dest, entno);
1295 WriteByte(dest, chan);
1296 if (sflags & SND_LARGESOUND)
1297 WriteShort(dest, idx);
1299 WriteByte(dest, idx);
1300 WriteCoord(dest, e.origin_x);
1301 WriteCoord(dest, e.origin_y);
1302 WriteCoord(dest, e.origin_z);
1306 WriteByte(dest, SVC_STOPSOUND);
1307 WriteShort(dest, entno * 8 + chan);
1310 void stopsound(entity e, float chan)
1312 if (!sound_allowed(MSG_BROADCAST, e))
1315 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1316 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1319 void play2(entity e, string filename)
1321 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1323 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
1326 .float announcetime;
1327 float announce(entity player, string msg)
1329 if (time > player.announcetime)
1330 if (clienttype(player) == CLIENTTYPE_REAL)
1332 player.announcetime = time + 0.8;
1338 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1339 float spamsound(entity e, float chan, string samp, float vol, float atten)
1341 if (!sound_allowed(MSG_BROADCAST, e))
1344 if (time > e.announcetime)
1346 e.announcetime = time;
1347 sound(e, chan, samp, vol, atten);
1353 void play2team(float t, string filename)
1357 if (cvar("bot_sound_monopoly"))
1360 FOR_EACH_REALPLAYER(head)
1363 play2(head, filename);
1367 void play2all(string samp)
1369 if (cvar("bot_sound_monopoly"))
1372 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
1375 void PrecachePlayerSounds(string f);
1376 void precache_all_models(string pattern)
1378 float globhandle, i, n;
1381 globhandle = search_begin(pattern, TRUE, FALSE);
1384 n = search_getsize(globhandle);
1385 for (i = 0; i < n; ++i)
1387 //print(search_getfilename(globhandle, i), "\n");
1388 f = search_getfilename(globhandle, i);
1391 if(substring(f, -9,5) == "_lod1")
1393 if(substring(f, -9,5) == "_lod2")
1395 if(!sv_loddistance1)
1397 PrecachePlayerSounds(strcat(f, ".sounds"));
1399 search_end(globhandle);
1404 // gamemode related things
1405 precache_model ("models/misc/chatbubble.spr");
1406 precache_model ("models/misc/teambubble.spr");
1409 precache_model ("models/runematch/curse.mdl");
1410 precache_model ("models/runematch/rune.mdl");
1413 #ifdef TTURRETS_ENABLED
1414 if (cvar("g_turrets"))
1418 // Precache all player models if desired
1419 if (cvar("sv_precacheplayermodels"))
1421 PrecachePlayerSounds("sound/player/default.sounds");
1422 precache_all_models("models/player/*.zym");
1423 precache_all_models("models/player/*.dpm");
1424 precache_all_models("models/player/*.md3");
1425 precache_all_models("models/player/*.psk");
1426 //precache_model("models/player/carni.zym");
1427 //precache_model("models/player/crash.zym");
1428 //precache_model("models/player/grunt.zym");
1429 //precache_model("models/player/headhunter.zym");
1430 //precache_model("models/player/insurrectionist.zym");
1431 //precache_model("models/player/jeandarc.zym");
1432 //precache_model("models/player/lurk.zym");
1433 //precache_model("models/player/lycanthrope.zym");
1434 //precache_model("models/player/marine.zym");
1435 //precache_model("models/player/nexus.zym");
1436 //precache_model("models/player/pyria.zym");
1437 //precache_model("models/player/shock.zym");
1438 //precache_model("models/player/skadi.zym");
1439 //precache_model("models/player/specop.zym");
1440 //precache_model("models/player/visitant.zym");
1443 if (cvar("sv_defaultcharacter"))
1446 s = cvar_string("sv_defaultplayermodel_red");
1450 PrecachePlayerSounds(strcat(s, ".sounds"));
1452 s = cvar_string("sv_defaultplayermodel_blue");
1456 PrecachePlayerSounds(strcat(s, ".sounds"));
1458 s = cvar_string("sv_defaultplayermodel_yellow");
1462 PrecachePlayerSounds(strcat(s, ".sounds"));
1464 s = cvar_string("sv_defaultplayermodel_pink");
1468 PrecachePlayerSounds(strcat(s, ".sounds"));
1470 s = cvar_string("sv_defaultplayermodel");
1474 PrecachePlayerSounds(strcat(s, ".sounds"));
1480 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1481 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1484 // gore and miscellaneous sounds
1485 //precache_sound ("misc/h2ohit.wav");
1486 precache_model ("models/hook.md3");
1487 precache_sound ("misc/armorimpact.wav");
1488 precache_sound ("misc/bodyimpact1.wav");
1489 precache_sound ("misc/bodyimpact2.wav");
1490 precache_sound ("misc/gib.wav");
1491 precache_sound ("misc/gib_splat01.wav");
1492 precache_sound ("misc/gib_splat02.wav");
1493 precache_sound ("misc/gib_splat03.wav");
1494 precache_sound ("misc/gib_splat04.wav");
1495 precache_sound ("misc/hit.wav");
1496 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1497 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1498 precache_sound ("misc/null.wav");
1499 precache_sound ("misc/spawn.wav");
1500 precache_sound ("misc/talk.wav");
1501 precache_sound ("misc/teleport.wav");
1502 precache_sound ("misc/poweroff.wav");
1503 precache_sound ("player/lava.wav");
1504 precache_sound ("player/slime.wav");
1507 precache_sound ("misc/jetpack_fly.wav");
1509 // announcer sounds - male
1510 precache_sound ("announcer/male/electrobitch.wav");
1511 precache_sound ("announcer/male/airshot.wav");
1512 precache_sound ("announcer/male/03kills.wav");
1513 precache_sound ("announcer/male/05kills.wav");
1514 precache_sound ("announcer/male/10kills.wav");
1515 precache_sound ("announcer/male/15kills.wav");
1516 precache_sound ("announcer/male/20kills.wav");
1517 precache_sound ("announcer/male/25kills.wav");
1518 precache_sound ("announcer/male/30kills.wav");
1519 precache_sound ("announcer/male/botlike.wav");
1520 precache_sound ("announcer/male/yoda.wav");
1521 precache_sound ("announcer/male/amazing.wav");
1522 precache_sound ("announcer/male/awesome.wav");
1523 precache_sound ("announcer/male/headshot.wav");
1524 precache_sound ("announcer/male/impressive.wav");
1526 // announcer sounds - robotic
1527 precache_sound ("announcer/robotic/prepareforbattle.wav");
1528 precache_sound ("announcer/robotic/begin.wav");
1529 precache_sound ("announcer/robotic/timeoutcalled.wav");
1530 precache_sound ("announcer/robotic/1fragleft.wav");
1531 precache_sound ("announcer/robotic/2fragsleft.wav");
1532 precache_sound ("announcer/robotic/3fragsleft.wav");
1533 precache_sound ("announcer/robotic/terminated.wav");
1536 precache_sound ("announcer/robotic/lastsecond.wav");
1537 precache_sound ("announcer/robotic/narrowly.wav");
1540 precache_model ("models/sprites/0.spr32");
1541 precache_model ("models/sprites/1.spr32");
1542 precache_model ("models/sprites/2.spr32");
1543 precache_model ("models/sprites/3.spr32");
1544 precache_model ("models/sprites/4.spr32");
1545 precache_model ("models/sprites/5.spr32");
1546 precache_model ("models/sprites/6.spr32");
1547 precache_model ("models/sprites/7.spr32");
1548 precache_model ("models/sprites/8.spr32");
1549 precache_model ("models/sprites/9.spr32");
1550 precache_model ("models/sprites/10.spr32");
1551 precache_sound ("announcer/robotic/1.wav");
1552 precache_sound ("announcer/robotic/2.wav");
1553 precache_sound ("announcer/robotic/3.wav");
1554 precache_sound ("announcer/robotic/4.wav");
1555 precache_sound ("announcer/robotic/5.wav");
1556 precache_sound ("announcer/robotic/6.wav");
1557 precache_sound ("announcer/robotic/7.wav");
1558 precache_sound ("announcer/robotic/8.wav");
1559 precache_sound ("announcer/robotic/9.wav");
1560 precache_sound ("announcer/robotic/10.wav");
1562 // common weapon precaches
1563 precache_sound ("weapons/weapon_switch.wav");
1564 precache_sound ("weapons/weaponpickup.wav");
1565 precache_sound ("weapons/unavailable.wav");
1566 if (g_grappling_hook)
1568 precache_sound ("weapons/hook_fire.wav"); // hook
1569 precache_sound ("weapons/hook_impact.wav"); // hook
1572 if (cvar("sv_precacheweapons") || g_nixnex)
1574 //precache weapon models/sounds
1577 while (wep <= WEP_LAST)
1579 weapon_action(wep, WR_PRECACHE);
1584 precache_model("models/elaser.mdl");
1585 precache_model("models/laser.mdl");
1586 precache_model("models/ebomb.mdl");
1589 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1591 if (!self.noise && self.music) // quake 3 uses the music field
1592 self.noise = self.music;
1594 // plays music for the level if there is any
1597 precache_sound (self.noise);
1598 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1603 // sorry, but using \ in macros breaks line numbers
1604 #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
1605 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
1606 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
1608 vector ExactTriggerHit_mins;
1609 vector ExactTriggerHit_maxs;
1610 float ExactTriggerHit_Recurse()
1616 tracebox('0 0 0', ExactTriggerHit_mins, ExactTriggerHit_maxs, '0 0 0', MOVE_NORMAL, other);
1619 if (trace_ent == self)
1624 se.solid = SOLID_NOT;
1625 f = ExactTriggerHit_Recurse();
1631 float ExactTriggerHit()
1635 if not(self.modelindex)
1639 self.solid = SOLID_BSP;
1640 ExactTriggerHit_mins = other.absmin;
1641 ExactTriggerHit_maxs = other.absmax;
1642 f = ExactTriggerHit_Recurse();
1648 // WARNING: this kills the trace globals
1649 #define EXACTTRIGGER_TOUCH if not(ExactTriggerHit()) return
1650 #define EXACTTRIGGER_INIT InitSolidBSPTrigger(); self.solid = SOLID_TRIGGER
1652 #define INITPRIO_FIRST 0
1653 #define INITPRIO_GAMETYPE 0
1654 #define INITPRIO_GAMETYPE_FALLBACK 1
1655 #define INITPRIO_CVARS 5
1656 #define INITPRIO_FINDTARGET 10
1657 #define INITPRIO_DROPTOFLOOR 20
1658 #define INITPRIO_SETLOCATION 90
1659 #define INITPRIO_LINKDOORS 91
1660 #define INITPRIO_LAST 99
1662 .void(void) initialize_entity;
1663 .float initialize_entity_order;
1664 .entity initialize_entity_next;
1665 entity initialize_entity_first;
1667 void make_safe_for_remove(entity e)
1669 if (e.initialize_entity)
1672 for (ent = initialize_entity_first; ent; )
1674 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1676 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1677 // skip it in linked list
1680 prev.initialize_entity_next = ent.initialize_entity_next;
1681 ent = prev.initialize_entity_next;
1685 initialize_entity_first = ent.initialize_entity_next;
1686 ent = initialize_entity_first;
1692 ent = ent.initialize_entity_next;
1698 void objerror(string s)
1700 make_safe_for_remove(self);
1701 objerror_builtin(s);
1704 void remove_unsafely(entity e)
1709 void remove_safely(entity e)
1711 make_safe_for_remove(e);
1715 void InitializeEntity(entity e, void(void) func, float order)
1719 if (!e || e.initialize_entity)
1721 // make a proxy initializer entity
1725 e.classname = "initialize_entity";
1729 e.initialize_entity = func;
1730 e.initialize_entity_order = order;
1732 cur = initialize_entity_first;
1735 if (!cur || cur.initialize_entity_order > order)
1737 // insert between prev and cur
1739 prev.initialize_entity_next = e;
1741 initialize_entity_first = e;
1742 e.initialize_entity_next = cur;
1746 cur = cur.initialize_entity_next;
1749 void InitializeEntitiesRun()
1752 startoflist = initialize_entity_first;
1753 initialize_entity_first = world;
1754 for (self = startoflist; self; )
1757 var void(void) func;
1758 e = self.initialize_entity_next;
1759 func = self.initialize_entity;
1760 self.initialize_entity_order = 0;
1761 self.initialize_entity = func_null;
1762 self.initialize_entity_next = world;
1763 if (self.classname == "initialize_entity")
1767 remove_builtin(self);
1770 //dprint("Delayed initialization: ", self.classname, "\n");
1776 .float uncustomizeentityforclient_set;
1777 .void(void) uncustomizeentityforclient;
1778 void(void) SUB_Nullpointer = #0;
1779 void UncustomizeEntitiesRun()
1783 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1784 self.uncustomizeentityforclient();
1787 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1789 e.customizeentityforclient = customizer;
1790 e.uncustomizeentityforclient = uncustomizer;
1791 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1795 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1798 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1802 if (e.classname == "")
1803 e.classname = "net_linked";
1805 if (e.model == "" || self.modelindex == 0)
1809 setmodel(e, "null");
1813 e.SendEntity = sendfunc;
1814 e.SendFlags = 0xFFFFFF;
1817 e.effects |= EF_NODEPTHTEST;
1821 e.nextthink = time + dt;
1822 e.think = SUB_Remove;
1826 void adaptor_think2touch()
1835 void adaptor_think2use()
1847 // deferred dropping
1848 void DropToFloor_Handler()
1850 droptofloor_builtin();
1851 self.dropped_origin = self.origin;
1856 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1861 float trace_hits_box_a0, trace_hits_box_a1;
1863 float trace_hits_box_1d(float end, float thmi, float thma)
1867 // just check if x is in range
1875 // do the trace with respect to x
1876 // 0 -> end has to stay in thmi -> thma
1877 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1878 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1879 if (trace_hits_box_a0 > trace_hits_box_a1)
1885 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1890 // now it is a trace from 0 to end
1892 trace_hits_box_a0 = 0;
1893 trace_hits_box_a1 = 1;
1895 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1897 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1899 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1905 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1907 return trace_hits_box(start, end, thmi - ma, thma - mi);
1910 float SUB_NoImpactCheck()
1912 // zero hitcontents = this is not the real impact, but either the
1913 // mirror-impact of something hitting the projectile instead of the
1914 // projectile hitting the something, or a touchareagrid one. Neither of
1915 // these stop the projectile from moving, so...
1916 if(trace_dphitcontents == 0)
1918 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1921 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1923 if (other == world && self.size != '0 0 0')
1926 tic = self.velocity * sys_ticrate;
1927 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1928 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1929 if (trace_fraction >= 1)
1931 dprint("Odd... did not hit...?\n");
1933 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1935 dprint("Detected and prevented the sky-grapple bug.\n");
1943 #define SUB_OwnerCheck() (other && (other == self.owner))
1945 #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)
1947 float MAX_IPBAN_URIS = 16;
1949 float URI_GET_DISCARD = 0;
1950 float URI_GET_IPBAN = 1;
1951 float URI_GET_IPBAN_END = 16;
1953 void URI_Get_Callback(float id, float status, string data)
1955 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
1957 dprint("\nEnd of data.\n");
1959 if (id == URI_GET_DISCARD)
1963 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1966 OnlineBanList_URI_Get_Callback(id, status, data);
1970 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1974 void print_to(entity e, string s)
1977 sprint(e, strcat(s, "\n"));
1996 for (i = 0; i < MapInfo_count; ++i)
1998 if (MapInfo_Get_ByID(i))
2000 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
2003 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
2004 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
2012 for (i = 0; i < MapInfo_count; ++i)
2014 if (MapInfo_Get_ByID(i))
2016 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/racerecord/time")));
2019 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/racerecord/netname"));
2020 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, mmsss(r)), " ", h, "\n");
2028 for (i = 0; i < MapInfo_count; ++i)
2030 if (MapInfo_Get_ByID(i))
2032 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/ctsrecord/time")));
2035 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/ctsrecord/netname"));
2036 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, mmsss(r)), " ", h, "\n");
2042 MapInfo_ClearTemps();
2045 return "No records are available on this server.\n";
2047 return strcat("Records on this server:\n", s);
2050 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2053 vector start, org, delta, end, enddown, mstart;
2055 m = e.dphitcontentsmask;
2056 e.dphitcontentsmask = goodcontents | badcontents;
2059 delta = world.maxs - world.mins;
2061 for (i = 0; i < attempts; ++i)
2063 start_x = org_x + random() * delta_x;
2064 start_y = org_y + random() * delta_y;
2065 start_z = org_z + random() * delta_z;
2067 // rule 1: start inside world bounds, and outside
2068 // solid, and don't start from somewhere where you can
2069 // fall down to evil
2070 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2071 if (trace_fraction >= 1)
2073 if (trace_startsolid)
2075 if (trace_dphitcontents & badcontents)
2077 if (trace_dphitq3surfaceflags & badsurfaceflags)
2080 // rule 2: if we are too high, lower the point
2081 if (trace_fraction * delta_z > maxaboveground)
2082 start = trace_endpos + '0 0 1' * maxaboveground;
2083 enddown = trace_endpos;
2085 // rule 3: make sure we aren't outside the map. This only works
2086 // for somewhat well formed maps. A good rule of thumb is that
2087 // the map should have a convex outside hull.
2088 // these can be traceLINES as we already verified the starting box
2089 mstart = start + 0.5 * (e.mins + e.maxs);
2090 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2091 if (trace_fraction >= 1)
2093 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2094 if (trace_fraction >= 1)
2096 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2097 if (trace_fraction >= 1)
2099 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2100 if (trace_fraction >= 1)
2102 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2103 if (trace_fraction >= 1)
2106 // find a random vector to "look at"
2107 end_x = org_x + random() * delta_x;
2108 end_y = org_y + random() * delta_y;
2109 end_z = org_z + random() * delta_z;
2110 end = start + normalize(end - start) * vlen(delta);
2112 // rule 4: start TO end must not be too short
2113 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2114 if (trace_startsolid)
2116 if (trace_fraction < minviewdistance / vlen(delta))
2119 // rule 5: don't want to look at sky
2120 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2123 // rule 6: we must not end up in trigger_hurt
2124 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2126 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
2133 e.dphitcontentsmask = m;
2137 setorigin(e, start);
2138 e.angles = vectoangles(end - start);
2139 dprint("Needed ", ftos(i + 1), " attempts\n");
2146 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2148 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2149 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2150 WriteShort(MSG_BROADCAST, effectno);
2151 WriteCoord(MSG_BROADCAST, start_x);
2152 WriteCoord(MSG_BROADCAST, start_y);
2153 WriteCoord(MSG_BROADCAST, start_z);
2154 WriteCoord(MSG_BROADCAST, end_x);
2155 WriteCoord(MSG_BROADCAST, end_y);
2156 WriteCoord(MSG_BROADCAST, end_z);
2157 WriteCoord(MSG_BROADCAST, end_dz);
2158 WriteShort(MSG_BROADCAST, spd / 16);
2161 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2164 vector vecxy, velxy;
2166 vecxy = end - start;
2171 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2173 trailparticles(world, effectno, start, end);
2177 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2178 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2181 string GetGametype(); // g_world.qc
2182 void write_recordmarker(entity pl, float tstart, float dt)
2184 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2186 // also write a marker into demo files for demotc-race-record-extractor to find
2189 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", mmsss(dt * 10)),
2190 " ", ftos(tstart), " ", ftos(dt), "\n"));
2193 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
2195 switch(self.owner.cvar_cl_gunalign)
2206 if(allowcenter) // 2: allow center handedness
2219 if(allowcenter) // 2: allow center handedness
2235 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2240 if (cvar("g_shootfromeye"))
2244 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2252 else if (cvar("g_shootfromcenter"))
2256 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
2264 else if (cvar("g_shootfromclient"))
2266 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
2268 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
2283 void attach_sameorigin(entity e, entity to, string tag)
2285 vector org, t_forward, t_left, t_up, e_forward, e_up;
2292 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2293 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2294 t_forward = v_forward * tagscale;
2295 t_left = v_right * -tagscale;
2296 t_up = v_up * tagscale;
2298 e.origin_x = org * t_forward;
2299 e.origin_y = org * t_left;
2300 e.origin_z = org * t_up;
2302 // current forward and up directions
2303 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2304 e.angles_x = -e.angles_x;
2305 fixedmakevectors(e.angles);
2307 // untransform forward, up!
2308 e_forward_x = v_forward * t_forward;
2309 e_forward_y = v_forward * t_left;
2310 e_forward_z = v_forward * t_up;
2311 e_up_x = v_up * t_forward;
2312 e_up_y = v_up * t_left;
2313 e_up_z = v_up * t_up;
2315 e.angles = fixedvectoangles2(e_forward, e_up);
2316 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2317 e.angles_x = -e.angles_x;
2319 setattachment(e, to, tag);
2320 setorigin(e, e.origin);
2323 void detach_sameorigin(entity e)
2326 org = gettaginfo(e, 0);
2327 e.angles = fixedvectoangles2(v_forward, v_up);
2328 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2329 e.angles_x = -e.angles_x;
2331 setattachment(e, world, "");
2332 setorigin(e, e.origin);
2335 void follow_sameorigin(entity e, entity to)
2337 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2338 e.aiment = to; // make the hole follow bmodel
2339 e.punchangle = to.angles; // the original angles of bmodel
2340 e.view_ofs = e.origin - to.origin; // relative origin
2341 e.v_angle = e.angles - to.angles; // relative angles
2344 void unfollow_sameorigin(entity e)
2346 e.movetype = MOVETYPE_NONE;
2349 entity gettaginfo_relative_ent;
2350 vector gettaginfo_relative(entity e, float tag)
2352 if (!gettaginfo_relative_ent)
2354 gettaginfo_relative_ent = spawn();
2355 gettaginfo_relative_ent.effects = EF_NODRAW;
2357 gettaginfo_relative_ent.model = e.model;
2358 gettaginfo_relative_ent.modelindex = e.modelindex;
2359 gettaginfo_relative_ent.frame = e.frame;
2360 return gettaginfo(gettaginfo_relative_ent, tag);
2363 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2367 if (pl.soundentity.cnt & p)
2369 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2370 pl.soundentity.cnt |= p;
2373 void SoundEntity_StopSound(entity pl, float chan)
2377 if (pl.soundentity.cnt & p)
2379 stopsoundto(MSG_ALL, pl.soundentity, chan);
2380 pl.soundentity.cnt &~= p;
2384 void SoundEntity_Attach(entity pl)
2386 pl.soundentity = spawn();
2387 pl.soundentity.classname = "soundentity";
2388 pl.soundentity.owner = pl;
2389 setattachment(pl.soundentity, pl, "");
2390 setmodel(pl.soundentity, "null");
2393 void SoundEntity_Detach(entity pl)
2396 for (i = 0; i <= 7; ++i)
2397 SoundEntity_StopSound(pl, i);
2401 float ParseCommandPlayerSlotTarget_firsttoken;
2402 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
2410 ParseCommandPlayerSlotTarget_firsttoken = -1;
2414 if (substring(argv(idx), 0, 1) == "#")
2416 s = substring(argv(idx), 1, -1);
2424 if (s == ftos(stof(s)))
2426 e = edict_num(stof(s));
2427 if (e.flags & FL_CLIENT)
2429 ParseCommandPlayerSlotTarget_firsttoken = idx;
2436 // it must be a nick name
2441 FOR_EACH_CLIENT(head)
2442 if (head.netname == s)
2449 ParseCommandPlayerSlotTarget_firsttoken = idx;
2453 s = strdecolorize(s);
2455 FOR_EACH_CLIENT(head)
2456 if (strdecolorize(head.netname) == s)
2463 ParseCommandPlayerSlotTarget_firsttoken = idx;
2474 float modeleffect_SendEntity(entity to, float sf)
2477 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2480 if(self.velocity != '0 0 0')
2482 if(self.angles != '0 0 0')
2484 if(self.avelocity != '0 0 0')
2487 WriteByte(MSG_ENTITY, f);
2488 WriteShort(MSG_ENTITY, self.modelindex);
2489 WriteByte(MSG_ENTITY, self.frame);
2490 WriteCoord(MSG_ENTITY, self.origin_x);
2491 WriteCoord(MSG_ENTITY, self.origin_y);
2492 WriteCoord(MSG_ENTITY, self.origin_z);
2495 WriteCoord(MSG_ENTITY, self.velocity_x);
2496 WriteCoord(MSG_ENTITY, self.velocity_y);
2497 WriteCoord(MSG_ENTITY, self.velocity_z);
2501 WriteCoord(MSG_ENTITY, self.angles_x);
2502 WriteCoord(MSG_ENTITY, self.angles_y);
2503 WriteCoord(MSG_ENTITY, self.angles_z);
2507 WriteCoord(MSG_ENTITY, self.avelocity_x);
2508 WriteCoord(MSG_ENTITY, self.avelocity_y);
2509 WriteCoord(MSG_ENTITY, self.avelocity_z);
2511 WriteShort(MSG_ENTITY, self.scale * 256.0);
2512 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2513 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2514 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2515 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2520 void modeleffect_spawn(string m, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2)
2525 e.classname = "modeleffect";
2533 e.teleport_time = t1;
2537 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2541 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2544 setsize(e, e.mins * sz, e.maxs * sz);
2545 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2548 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2550 modeleffect_spawn(m, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);