1 var void remove(entity e);
2 void objerror(string s);
4 .vector dropped_origin;
6 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
7 void crosshair_trace(entity pl)
9 traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
11 void crosshair_trace_plusvisibletriggers(entity pl)
15 first = findchainfloat(solid, SOLID_TRIGGER);
17 for (e = first; e; e = e.chain)
23 for (e = first; e; e = e.chain)
24 e.solid = SOLID_TRIGGER;
26 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
27 void WarpZone_crosshair_trace(entity pl)
29 WarpZone_traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
32 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
33 void() spawnpoint_use;
36 string admin_name(void)
38 if(autocvar_sv_adminnick != "")
39 return autocvar_sv_adminnick;
41 return "SERVER ADMIN";
44 float DistributeEvenly_amount;
45 float DistributeEvenly_totalweight;
46 void DistributeEvenly_Init(float amount, float totalweight)
48 if (DistributeEvenly_amount)
50 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
51 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
54 DistributeEvenly_amount = 0;
56 DistributeEvenly_amount = amount;
57 DistributeEvenly_totalweight = totalweight;
59 float DistributeEvenly_Get(float weight)
64 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
65 DistributeEvenly_totalweight -= weight;
66 DistributeEvenly_amount -= f;
69 float DistributeEvenly_GetRandomized(float weight)
74 f = floor(random() + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
75 DistributeEvenly_totalweight -= weight;
76 DistributeEvenly_amount -= f;
80 #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
82 string STR_PLAYER = "player";
83 string STR_SPECTATOR = "spectator";
84 string STR_OBSERVER = "observer";
86 #define IS_PLAYER(v) (v.classname == STR_PLAYER)
87 #define IS_SPEC(v) (v.classname == STR_SPECTATOR)
88 #define IS_OBSERVER(v) (v.classname == STR_OBSERVER)
89 #define IS_CLIENT(v) (v.flags & FL_CLIENT)
90 #define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT)
91 #define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL)
92 #define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT)
94 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
95 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v))
96 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v))
98 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v))
99 #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if not(IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too
100 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v))
102 #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
104 // copies a string to a tempstring (so one can strunzone it)
105 string strcat1(string s) = #115; // FRIK_FILE
110 void GameLogEcho(string s)
115 if (autocvar_sv_eventlog_files)
120 matches = autocvar_sv_eventlog_files_counter + 1;
121 cvar_set("sv_eventlog_files_counter", ftos(matches));
124 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
125 fn = strcat(autocvar_sv_eventlog_files_nameprefix, fn, autocvar_sv_eventlog_files_namesuffix);
126 logfile = fopen(fn, FILE_APPEND);
127 fputs(logfile, ":logversion:3\n");
131 if (autocvar_sv_eventlog_files_timestamps)
132 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
134 fputs(logfile, strcat(s, "\n"));
137 if (autocvar_sv_eventlog_console)
146 // will be opened later
151 if (logfile_open && logfile >= 0)
158 float spawnpoint_nag;
159 void relocate_spawnpoint()
161 // nudge off the floor
162 setorigin(self, self.origin + '0 0 1');
164 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
165 if (trace_startsolid)
171 if (!move_out_of_solid(self))
172 objerror("could not get out of solid at all!");
173 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
174 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
175 print(" ", ftos(self.origin_y - o_y));
176 print(" ", ftos(self.origin_z - o_z), "'\n");
177 if (autocvar_g_spawnpoints_auto_move_out_of_solid)
180 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
186 self.mins = self.maxs = '0 0 0';
187 objerror("player spawn point in solid, mapper sucks!\n");
192 self.use = spawnpoint_use;
193 self.team_saved = self.team;
197 if (have_team_spawns != 0)
199 have_team_spawns = 1;
200 have_team_spawns_forteam[self.team] = 1;
202 if (autocvar_r_showbboxes)
204 // show where spawnpoints point at too
205 makevectors(self.angles);
208 e.classname = "info_player_foo";
209 setorigin(e, self.origin + v_forward * 24);
210 setsize(e, '-8 -8 -8', '8 8 8');
211 e.solid = SOLID_TRIGGER;
215 #define strstr strstrofs
217 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
218 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
219 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
220 // BE CONSTANT OR strzoneD!
221 float strstr(string haystack, string needle, float offset)
225 len = strlen(needle);
226 endpos = strlen(haystack) - len;
227 while(offset <= endpos)
229 found = substring(haystack, offset, len);
238 float NUM_NEAREST_ENTITIES = 4;
239 entity nearest_entity[NUM_NEAREST_ENTITIES];
240 float nearest_length[NUM_NEAREST_ENTITIES];
241 entity findnearest(vector point, .string field, string value, vector axismod)
252 localhead = find(world, field, value);
255 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
256 dist = localhead.oldorigin;
258 dist = localhead.origin;
260 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
263 for (i = 0; i < num_nearest; ++i)
265 if (len < nearest_length[i])
269 // now i tells us where to insert at
270 // INSERTION SORT! YOU'VE SEEN IT! RUN!
271 if (i < NUM_NEAREST_ENTITIES)
273 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
275 nearest_length[j + 1] = nearest_length[j];
276 nearest_entity[j + 1] = nearest_entity[j];
278 nearest_length[i] = len;
279 nearest_entity[i] = localhead;
280 if (num_nearest < NUM_NEAREST_ENTITIES)
281 num_nearest = num_nearest + 1;
284 localhead = find(localhead, field, value);
287 // now use the first one from our list that we can see
288 for (i = 0; i < num_nearest; ++i)
290 traceline(point, nearest_entity[i].origin, TRUE, world);
291 if (trace_fraction == 1)
295 dprint("Nearest point (");
296 dprint(nearest_entity[0].netname);
297 dprint(") is not visible, using a visible one.\n");
299 return nearest_entity[i];
303 if (num_nearest == 0)
306 dprint("Not seeing any location point, using nearest as fallback.\n");
308 dprint("Candidates were: ");
309 for(j = 0; j < num_nearest; ++j)
313 dprint(nearest_entity[j].netname);
318 return nearest_entity[0];
321 void spawnfunc_target_location()
323 self.classname = "target_location";
324 // location name in netname
325 // eventually support: count, teamgame selectors, line of sight?
328 void spawnfunc_info_location()
330 self.classname = "target_location";
331 self.message = self.netname;
334 string NearestLocation(vector p)
339 loc = findnearest(p, classname, "target_location", '1 1 1');
346 loc = findnearest(p, target, "###item###", '1 1 4');
353 string formatmessage(string msg)
364 WarpZone_crosshair_trace(self);
365 cursor = trace_endpos;
366 cursor_ent = trace_ent;
370 break; // too many replacements
373 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
374 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
387 replacement = substring(msg, p, 2);
388 escape = substring(msg, p + 1, 1);
392 else if (escape == "\\")
394 else if (escape == "n")
396 else if (escape == "a")
397 replacement = ftos(floor(self.armorvalue));
398 else if (escape == "h")
399 replacement = ftos(floor(self.health));
400 else if (escape == "l")
401 replacement = NearestLocation(self.origin);
402 else if (escape == "y")
403 replacement = NearestLocation(cursor);
404 else if (escape == "d")
405 replacement = NearestLocation(self.death_origin);
406 else if (escape == "w") {
410 wep = self.switchweapon;
413 replacement = W_Name(wep);
414 } else if (escape == "W") {
415 if (self.items & IT_SHELLS) replacement = "shells";
416 else if (self.items & IT_NAILS) replacement = "bullets";
417 else if (self.items & IT_ROCKETS) replacement = "rockets";
418 else if (self.items & IT_CELLS) replacement = "cells";
419 else replacement = "batteries"; // ;)
420 } else if (escape == "x") {
421 replacement = cursor_ent.netname;
422 if (replacement == "" || !cursor_ent)
423 replacement = "nothing";
424 } else if (escape == "s")
425 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
426 else if (escape == "S")
427 replacement = ftos(vlen(self.velocity));
429 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
430 p = p + strlen(replacement);
435 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
436 return (value == 0) ? FALSE : TRUE;
445 >0: receives a cvar from name=argv(f) value=argv(f+1)
447 void GetCvars_handleString(string thisname, float f, .string field, string name)
452 strunzone(self.field);
453 self.field = string_null;
457 if (thisname == name)
460 strunzone(self.field);
461 self.field = strzone(argv(f + 1));
465 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
467 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
469 GetCvars_handleString(thisname, f, field, name);
470 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
471 if (thisname == name)
474 s = func(strcat1(self.field));
477 strunzone(self.field);
478 self.field = strzone(s);
482 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
489 if (thisname == name)
490 self.field = stof(argv(f + 1));
493 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
495 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
502 if (thisname == name)
506 self.field = stof(argv(f + 1));
515 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
518 float w_getbestweapon(entity e);
519 string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(string wo)
522 o = W_FixWeaponOrder_ForceComplete(wo);
523 if(self.weaponorder_byimpulse)
525 strunzone(self.weaponorder_byimpulse);
526 self.weaponorder_byimpulse = string_null;
528 self.weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
531 void GetCvars(float f)
533 string s = string_null;
536 s = strcat1(argv(f));
541 MUTATOR_CALLHOOK(GetCvars);
543 Notification_GetCvars();
545 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
546 GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
547 GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
548 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
549 GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
550 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
551 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
552 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
553 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
554 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
555 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
556 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
557 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
558 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
559 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
560 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
561 GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode");
562 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
563 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
564 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
565 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
566 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
567 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
569 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
570 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
572 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
573 GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
574 GetCvars_handleFloat(s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
575 GetCvars_handleFloat(s, f, cvar_cl_movement_track_canjump, "cl_movement_track_canjump");
576 GetCvars_handleFloat(s, f, cvar_cl_newusekeysupported, "cl_newusekeysupported");
578 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
581 if (s == "cl_weaponpriority")
582 self.switchweapon = w_getbestweapon(self);
583 if (s == "cl_allow_uidtracking")
584 PlayerStats_AddPlayer(self);
588 // decolorizes and team colors the player name when needed
589 string playername(entity p)
592 if (teamplay && !intermission_running && p.classname == "player")
594 t = Team_ColorCode(p.team);
595 return strcat(t, strdecolorize(p.netname));
601 vector randompos(vector m1, vector m2)
605 v_x = m2_x * random() + m1_x;
606 v_y = m2_y * random() + m1_y;
607 v_z = m2_z * random() + m1_z;
611 //#NO AUTOCVARS START
613 float g_pickup_shells;
614 float g_pickup_shells_max;
615 float g_pickup_nails;
616 float g_pickup_nails_max;
617 float g_pickup_rockets;
618 float g_pickup_rockets_max;
619 float g_pickup_cells;
620 float g_pickup_cells_max;
622 float g_pickup_fuel_jetpack;
623 float g_pickup_fuel_max;
624 float g_pickup_armorsmall;
625 float g_pickup_armorsmall_max;
626 float g_pickup_armorsmall_anyway;
627 float g_pickup_armormedium;
628 float g_pickup_armormedium_max;
629 float g_pickup_armormedium_anyway;
630 float g_pickup_armorbig;
631 float g_pickup_armorbig_max;
632 float g_pickup_armorbig_anyway;
633 float g_pickup_armorlarge;
634 float g_pickup_armorlarge_max;
635 float g_pickup_armorlarge_anyway;
636 float g_pickup_healthsmall;
637 float g_pickup_healthsmall_max;
638 float g_pickup_healthsmall_anyway;
639 float g_pickup_healthmedium;
640 float g_pickup_healthmedium_max;
641 float g_pickup_healthmedium_anyway;
642 float g_pickup_healthlarge;
643 float g_pickup_healthlarge_max;
644 float g_pickup_healthlarge_anyway;
645 float g_pickup_healthmega;
646 float g_pickup_healthmega_max;
647 float g_pickup_healthmega_anyway;
648 float g_pickup_ammo_anyway;
649 float g_pickup_weapons_anyway;
651 WEPSET_DECLARE_A(g_weaponarena_weapons);
652 float g_weaponarena_random;
653 float g_weaponarena_random_with_laser;
654 string g_weaponarena_list;
655 float g_weaponspeedfactor;
656 float g_weaponratefactor;
657 float g_weapondamagefactor;
658 float g_weaponforcefactor;
659 float g_weaponspreadfactor;
661 WEPSET_DECLARE_A(start_weapons);
662 WEPSET_DECLARE_A(start_weapons_default);
663 WEPSET_DECLARE_A(start_weapons_defaultmask);
665 float start_ammo_shells;
666 float start_ammo_nails;
667 float start_ammo_rockets;
668 float start_ammo_cells;
669 float start_ammo_fuel;
671 float start_armorvalue;
672 WEPSET_DECLARE_A(warmup_start_weapons);
673 WEPSET_DECLARE_A(warmup_start_weapons_default);
674 WEPSET_DECLARE_A(warmup_start_weapons_defaultmask);
675 float warmup_start_ammo_shells;
676 float warmup_start_ammo_nails;
677 float warmup_start_ammo_rockets;
678 float warmup_start_ammo_cells;
679 float warmup_start_ammo_fuel;
680 float warmup_start_health;
681 float warmup_start_armorvalue;
684 entity get_weaponinfo(float w);
686 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
688 var float i = weaponinfo.weapon;
694 if (g_lms || g_ca || allguns)
696 if(weaponinfo.spawnflags & WEP_FLAG_NORMAL)
702 d = (i == WEP_SHOTGUN);
704 d = 0; // weapon is set a few lines later
706 d = (i == WEP_LASER || i == WEP_SHOTGUN);
708 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
709 d |= (i == WEP_HOOK);
710 if(weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED) // never default mutator blocked guns
713 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
715 //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n"));
720 // 4: is set by default?
729 void readplayerstartcvars()
735 // initialize starting values for players
736 WEPSET_CLEAR_A(start_weapons);
737 WEPSET_CLEAR_A(start_weapons_default);
738 WEPSET_CLEAR_A(start_weapons_defaultmask);
740 start_ammo_shells = 0;
741 start_ammo_nails = 0;
742 start_ammo_rockets = 0;
743 start_ammo_cells = 0;
744 start_health = cvar("g_balance_health_start");
745 start_armorvalue = cvar("g_balance_armor_start");
748 WEPSET_CLEAR_A(g_weaponarena_weapons);
750 s = cvar_string("g_weaponarena");
751 if (s == "0" || s == "")
757 if (s == "0" || s == "")
763 // forcibly turn off weaponarena
768 g_weaponarena_list = "All Weapons";
769 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
771 e = get_weaponinfo(j);
772 if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
773 WEPSET_OR_AW(g_weaponarena_weapons, j);
776 else if (s == "most")
779 g_weaponarena_list = "Most Weapons";
780 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
782 e = get_weaponinfo(j);
783 if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
784 if (e.spawnflags & WEP_FLAG_NORMAL)
785 WEPSET_OR_AW(g_weaponarena_weapons, j);
788 else if (s == "none")
791 g_weaponarena_list = "No Weapons";
796 t = tokenize_console(s);
797 g_weaponarena_list = "";
798 for (i = 0; i < t; ++i)
801 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
803 e = get_weaponinfo(j);
806 WEPSET_OR_AW(g_weaponarena_weapons, j);
807 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
813 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
816 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
820 g_weaponarena_random = cvar("g_weaponarena_random");
822 g_weaponarena_random = 0;
823 g_weaponarena_random_with_laser = cvar("g_weaponarena_random_with_laser");
827 g_minstagib = 0; // incompatible
828 g_pinata = 0; // incompatible
829 g_weapon_stay = 0; // incompatible
830 WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons);
832 start_items |= IT_UNLIMITED_AMMO;
836 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
838 e = get_weaponinfo(i);
839 float w = want_weapon("g_start_weapon_", e, FALSE);
841 WEPSET_OR_AW(start_weapons, i);
843 WEPSET_OR_AW(start_weapons_default, i);
845 WEPSET_OR_AW(start_weapons_defaultmask, i);
849 if(!cvar("g_use_ammunition"))
850 start_items |= IT_UNLIMITED_AMMO;
852 if(cvar("g_nexball"))
853 start_items |= IT_UNLIMITED_SUPERWEAPONS; // FIXME BAD BAD BAD BAD HACK, NEXBALL SHOULDN'T ABUSE PORTO'S WEAPON SLOT
855 if(start_items & IT_UNLIMITED_WEAPON_AMMO)
857 start_ammo_rockets = 999;
858 start_ammo_shells = 999;
859 start_ammo_cells = 999;
860 start_ammo_nails = 999;
861 start_ammo_fuel = 999;
867 start_ammo_shells = cvar("g_lms_start_ammo_shells");
868 start_ammo_nails = cvar("g_lms_start_ammo_nails");
869 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
870 start_ammo_cells = cvar("g_lms_start_ammo_cells");
871 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
875 start_ammo_shells = cvar("g_start_ammo_shells");
876 start_ammo_nails = cvar("g_start_ammo_nails");
877 start_ammo_rockets = cvar("g_start_ammo_rockets");
878 start_ammo_cells = cvar("g_start_ammo_cells");
879 start_ammo_fuel = cvar("g_start_ammo_fuel");
885 start_health = cvar("g_lms_start_health");
886 start_armorvalue = cvar("g_lms_start_armor");
891 warmup_start_ammo_shells = start_ammo_shells;
892 warmup_start_ammo_nails = start_ammo_nails;
893 warmup_start_ammo_rockets = start_ammo_rockets;
894 warmup_start_ammo_cells = start_ammo_cells;
895 warmup_start_ammo_fuel = start_ammo_fuel;
896 warmup_start_health = start_health;
897 warmup_start_armorvalue = start_armorvalue;
898 WEPSET_COPY_AA(warmup_start_weapons, start_weapons);
899 WEPSET_COPY_AA(warmup_start_weapons_default, start_weapons_default);
900 WEPSET_COPY_AA(warmup_start_weapons_defaultmask, start_weapons_defaultmask);
902 if (!g_weaponarena && !g_minstagib && !g_ca)
904 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
905 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
906 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
907 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
908 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
909 warmup_start_health = cvar("g_warmup_start_health");
910 warmup_start_armorvalue = cvar("g_warmup_start_armor");
911 WEPSET_CLEAR_A(warmup_start_weapons);
912 WEPSET_CLEAR_A(warmup_start_weapons_default);
913 WEPSET_CLEAR_A(warmup_start_weapons_defaultmask);
914 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
916 e = get_weaponinfo(i);
917 float w = want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns"));
919 WEPSET_OR_AW(warmup_start_weapons, i);
921 WEPSET_OR_AW(warmup_start_weapons_default, i);
923 WEPSET_OR_AW(warmup_start_weapons_defaultmask, i);
929 start_items |= IT_JETPACK;
931 MUTATOR_CALLHOOK(SetStartItems);
933 if ((start_items & IT_JETPACK) || (g_grappling_hook && WEPSET_CONTAINS_AW(start_weapons, WEP_HOOK)))
935 g_grappling_hook = 0; // these two can't coexist, as they use the same button
936 start_items |= IT_FUEL_REGEN;
937 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
938 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
941 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
943 e = get_weaponinfo(i);
944 if(WEPSET_CONTAINS_AW(start_weapons, i) || WEPSET_CONTAINS_AW(warmup_start_weapons, i))
945 weapon_action(i, WR_PRECACHE);
948 start_ammo_shells = max(0, start_ammo_shells);
949 start_ammo_nails = max(0, start_ammo_nails);
950 start_ammo_cells = max(0, start_ammo_cells);
951 start_ammo_rockets = max(0, start_ammo_rockets);
952 start_ammo_fuel = max(0, start_ammo_fuel);
954 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
955 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
956 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
957 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
958 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
962 float g_bugrigs_planar_movement;
963 float g_bugrigs_planar_movement_car_jumping;
964 float g_bugrigs_reverse_spinning;
965 float g_bugrigs_reverse_speeding;
966 float g_bugrigs_reverse_stopping;
967 float g_bugrigs_air_steering;
968 float g_bugrigs_angle_smoothing;
969 float g_bugrigs_friction_floor;
970 float g_bugrigs_friction_brake;
971 float g_bugrigs_friction_air;
972 float g_bugrigs_accel;
973 float g_bugrigs_speed_ref;
974 float g_bugrigs_speed_pow;
975 float g_bugrigs_steer;
977 float g_touchexplode;
978 float g_touchexplode_radius;
979 float g_touchexplode_damage;
980 float g_touchexplode_edgedamage;
981 float g_touchexplode_force;
986 string GetGametype(); // g_world.qc
987 void readlevelcvars(void)
989 g_minstagib = cvar("g_minstagib");
991 // load ALL the mutators
992 if(cvar("g_dodging"))
993 MUTATOR_ADD(mutator_dodging);
994 if(cvar("g_spawn_near_teammate"))
995 MUTATOR_ADD(mutator_spawn_near_teammate);
996 if(cvar("g_physical_items"))
997 MUTATOR_ADD(mutator_physical_items);
998 if(cvar("g_minstagib"))
999 MUTATOR_ADD(mutator_minstagib);
1003 if(cvar("g_invincible_projectiles"))
1004 MUTATOR_ADD(mutator_invincibleprojectiles);
1005 if(cvar("g_new_toys"))
1006 MUTATOR_ADD(mutator_new_toys);
1008 MUTATOR_ADD(mutator_nix);
1009 if(cvar("g_rocket_flying"))
1010 MUTATOR_ADD(mutator_rocketflying);
1011 if(cvar("g_vampire"))
1012 MUTATOR_ADD(mutator_vampire);
1013 if(cvar("g_superspectate"))
1014 MUTATOR_ADD(mutator_superspec);
1017 // is this a mutator? is this a mode?
1018 if(cvar("g_sandbox"))
1019 MUTATOR_ADD(sandbox);
1021 if(cvar("sv_allow_fullbright"))
1022 serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
1024 g_bugrigs = cvar("g_bugrigs");
1025 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1026 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1027 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1028 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1029 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1030 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1031 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1032 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1033 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1034 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1035 g_bugrigs_accel = cvar("g_bugrigs_accel");
1036 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1037 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1038 g_bugrigs_steer = cvar("g_bugrigs_steer");
1040 g_touchexplode = cvar("g_touchexplode");
1041 g_touchexplode_radius = cvar("g_touchexplode_radius");
1042 g_touchexplode_damage = cvar("g_touchexplode_damage");
1043 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1044 g_touchexplode_force = cvar("g_touchexplode_force");
1046 sv_clones = cvar("sv_clones");
1047 sv_foginterval = cvar("sv_foginterval");
1048 g_cloaked = cvar("g_cloaked");
1050 g_cloaked = 1; // always enable cloak in CTS
1051 g_jump_grunt = cvar("g_jump_grunt");
1052 g_footsteps = cvar("g_footsteps");
1053 g_grappling_hook = cvar("g_grappling_hook");
1054 g_jetpack = cvar("g_jetpack");
1055 g_midair = cvar("g_midair");
1056 g_norecoil = cvar("g_norecoil");
1057 g_bloodloss = cvar("g_bloodloss");
1058 sv_maxidle = cvar("sv_maxidle");
1059 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1060 sv_autotaunt = cvar("sv_autotaunt");
1061 sv_taunt = cvar("sv_taunt");
1063 inWarmupStage = cvar("g_warmup");
1064 g_warmup_limit = cvar("g_warmup_limit");
1065 g_warmup_allguns = cvar("g_warmup_allguns");
1066 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1068 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
1069 inWarmupStage = 0; // these modes cannot work together, sorry
1071 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1072 g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
1073 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1074 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1075 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1076 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1077 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1078 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1079 g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
1080 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1081 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1082 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1083 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1084 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1086 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1087 g_weaponratefactor = cvar("g_weaponratefactor");
1088 g_weapondamagefactor = cvar("g_weapondamagefactor");
1089 g_weaponforcefactor = cvar("g_weaponforcefactor");
1090 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1092 g_pickup_shells = cvar("g_pickup_shells");
1093 g_pickup_shells_max = cvar("g_pickup_shells_max");
1094 g_pickup_nails = cvar("g_pickup_nails");
1095 g_pickup_nails_max = cvar("g_pickup_nails_max");
1096 g_pickup_rockets = cvar("g_pickup_rockets");
1097 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1098 g_pickup_cells = cvar("g_pickup_cells");
1099 g_pickup_cells_max = cvar("g_pickup_cells_max");
1100 g_pickup_fuel = cvar("g_pickup_fuel");
1101 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1102 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1103 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1104 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1105 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1106 g_pickup_armormedium = cvar("g_pickup_armormedium");
1107 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1108 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1109 g_pickup_armorbig = cvar("g_pickup_armorbig");
1110 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1111 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1112 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1113 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1114 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1115 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1116 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1117 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1118 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1119 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1120 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1121 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1122 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1123 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1124 g_pickup_healthmega = cvar("g_pickup_healthmega");
1125 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1126 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1128 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1129 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1131 g_pinata = cvar("g_pinata");
1133 g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
1135 g_weapon_stay = cvar("g_weapon_stay");
1137 if not(inWarmupStage && !g_ca)
1138 game_starttime = cvar("g_start_delay");
1140 readplayerstartcvars();
1146 string precache_sound (string s) = #19;
1147 float precache_sound_index (string s) = #19;
1149 #define SND_VOLUME 1
1150 #define SND_ATTENUATION 2
1151 #define SND_LARGEENTITY 8
1152 #define SND_LARGESOUND 16
1154 float sound_allowed(float dest, entity e)
1156 // sounds from world may always pass
1159 if (e.classname == "body")
1161 else if (e.realowner && e.realowner != e)
1163 else if (e.owner && e.owner != e)
1168 // sounds to self may always pass
1169 if (dest == MSG_ONE)
1170 if (e == msg_entity)
1172 // sounds by players can be removed
1173 if (autocvar_bot_sound_monopoly)
1174 if (clienttype(e) == CLIENTTYPE_REAL)
1176 // anything else may pass
1180 #ifdef COMPAT_XON010_CHANNELS
1181 void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
1182 void sound(entity e, float chan, string samp, float vol, float atten)
1184 if (!sound_allowed(MSG_BROADCAST, e))
1186 builtin_sound(e, chan, samp, vol, atten);
1190 void sound(entity e, float chan, string samp, float vol, float atten)
1192 if (!sound_allowed(MSG_BROADCAST, e))
1194 sound7(e, chan, samp, vol, atten, 0, 0);
1198 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1202 if (!sound_allowed(dest, e))
1205 entno = num_for_edict(e);
1206 idx = precache_sound_index(samp);
1211 atten = floor(atten * 64);
1212 vol = floor(vol * 255);
1215 sflags |= SND_VOLUME;
1217 sflags |= SND_ATTENUATION;
1218 if (entno >= 8192 || chan < 0 || chan > 7)
1219 sflags |= SND_LARGEENTITY;
1221 sflags |= SND_LARGESOUND;
1223 WriteByte(dest, SVC_SOUND);
1224 WriteByte(dest, sflags);
1225 if (sflags & SND_VOLUME)
1226 WriteByte(dest, vol);
1227 if (sflags & SND_ATTENUATION)
1228 WriteByte(dest, atten);
1229 if (sflags & SND_LARGEENTITY)
1231 WriteShort(dest, entno);
1232 WriteByte(dest, chan);
1236 WriteShort(dest, entno * 8 + chan);
1238 if (sflags & SND_LARGESOUND)
1239 WriteShort(dest, idx);
1241 WriteByte(dest, idx);
1243 WriteCoord(dest, o_x);
1244 WriteCoord(dest, o_y);
1245 WriteCoord(dest, o_z);
1247 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1251 if (!sound_allowed(dest, e))
1254 o = e.origin + 0.5 * (e.mins + e.maxs);
1255 soundtoat(dest, e, o, chan, samp, vol, atten);
1257 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1259 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, atten);
1261 void stopsoundto(float dest, entity e, float chan)
1265 if (!sound_allowed(dest, e))
1268 entno = num_for_edict(e);
1270 if (entno >= 8192 || chan < 0 || chan > 7)
1273 idx = precache_sound_index("misc/null.wav");
1274 sflags = SND_LARGEENTITY;
1276 sflags |= SND_LARGESOUND;
1277 WriteByte(dest, SVC_SOUND);
1278 WriteByte(dest, sflags);
1279 WriteShort(dest, entno);
1280 WriteByte(dest, chan);
1281 if (sflags & SND_LARGESOUND)
1282 WriteShort(dest, idx);
1284 WriteByte(dest, idx);
1285 WriteCoord(dest, e.origin_x);
1286 WriteCoord(dest, e.origin_y);
1287 WriteCoord(dest, e.origin_z);
1291 WriteByte(dest, SVC_STOPSOUND);
1292 WriteShort(dest, entno * 8 + chan);
1295 void stopsound(entity e, float chan)
1297 if (!sound_allowed(MSG_BROADCAST, e))
1300 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1301 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1304 void play2(entity e, string filename)
1306 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1308 soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTN_NONE);
1311 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1313 float spamsound(entity e, float chan, string samp, float vol, float atten)
1315 if (!sound_allowed(MSG_BROADCAST, e))
1318 if (time > e.spamtime)
1321 sound(e, chan, samp, vol, atten);
1327 void play2team(float t, string filename)
1331 if (autocvar_bot_sound_monopoly)
1334 FOR_EACH_REALPLAYER(head)
1337 play2(head, filename);
1341 void play2all(string samp)
1343 if (autocvar_bot_sound_monopoly)
1346 sound(world, CH_INFO, samp, VOL_BASE, ATTN_NONE);
1349 void PrecachePlayerSounds(string f);
1350 void precache_playermodel(string m)
1352 float globhandle, i, n;
1355 if(substring(m, -9,5) == "_lod1")
1357 if(substring(m, -9,5) == "_lod2")
1360 f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
1363 f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
1367 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1370 n = search_getsize(globhandle);
1371 for (i = 0; i < n; ++i)
1373 //print(search_getfilename(globhandle, i), "\n");
1374 f = search_getfilename(globhandle, i);
1375 PrecachePlayerSounds(f);
1377 search_end(globhandle);
1379 void precache_all_playermodels(string pattern)
1381 float globhandle, i, n;
1384 globhandle = search_begin(pattern, TRUE, FALSE);
1387 n = search_getsize(globhandle);
1388 for (i = 0; i < n; ++i)
1390 //print(search_getfilename(globhandle, i), "\n");
1391 f = search_getfilename(globhandle, i);
1392 precache_playermodel(f);
1394 search_end(globhandle);
1399 // gamemode related things
1400 precache_model ("models/misc/chatbubble.spr");
1402 #ifdef TTURRETS_ENABLED
1403 if (autocvar_g_turrets)
1407 // Precache all player models if desired
1408 if (autocvar_sv_precacheplayermodels)
1410 PrecachePlayerSounds("sound/player/default.sounds");
1411 precache_all_playermodels("models/player/*.zym");
1412 precache_all_playermodels("models/player/*.dpm");
1413 precache_all_playermodels("models/player/*.md3");
1414 precache_all_playermodels("models/player/*.psk");
1415 precache_all_playermodels("models/player/*.iqm");
1418 if (autocvar_sv_defaultcharacter)
1421 s = autocvar_sv_defaultplayermodel_red;
1423 precache_playermodel(s);
1424 s = autocvar_sv_defaultplayermodel_blue;
1426 precache_playermodel(s);
1427 s = autocvar_sv_defaultplayermodel_yellow;
1429 precache_playermodel(s);
1430 s = autocvar_sv_defaultplayermodel_pink;
1432 precache_playermodel(s);
1433 s = autocvar_sv_defaultplayermodel;
1435 precache_playermodel(s);
1440 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1441 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1444 // gore and miscellaneous sounds
1445 //precache_sound ("misc/h2ohit.wav");
1446 precache_model ("models/hook.md3");
1447 precache_sound ("misc/armorimpact.wav");
1448 precache_sound ("misc/bodyimpact1.wav");
1449 precache_sound ("misc/bodyimpact2.wav");
1450 precache_sound ("misc/gib.wav");
1451 precache_sound ("misc/gib_splat01.wav");
1452 precache_sound ("misc/gib_splat02.wav");
1453 precache_sound ("misc/gib_splat03.wav");
1454 precache_sound ("misc/gib_splat04.wav");
1455 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1456 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1457 precache_sound ("misc/null.wav");
1458 precache_sound ("misc/spawn.wav");
1459 precache_sound ("misc/talk.wav");
1460 precache_sound ("misc/teleport.wav");
1461 precache_sound ("misc/poweroff.wav");
1462 precache_sound ("player/lava.wav");
1463 precache_sound ("player/slime.wav");
1465 precache_model ("models/sprites/0.spr32");
1466 precache_model ("models/sprites/1.spr32");
1467 precache_model ("models/sprites/2.spr32");
1468 precache_model ("models/sprites/3.spr32");
1469 precache_model ("models/sprites/4.spr32");
1470 precache_model ("models/sprites/5.spr32");
1471 precache_model ("models/sprites/6.spr32");
1472 precache_model ("models/sprites/7.spr32");
1473 precache_model ("models/sprites/8.spr32");
1474 precache_model ("models/sprites/9.spr32");
1475 precache_model ("models/sprites/10.spr32");
1477 // common weapon precaches
1478 precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound here
1479 precache_sound ("weapons/weapon_switch.wav");
1480 precache_sound ("weapons/weaponpickup.wav");
1481 precache_sound ("weapons/unavailable.wav");
1482 precache_sound ("weapons/dryfire.wav");
1483 if (g_grappling_hook)
1485 precache_sound ("weapons/hook_fire.wav"); // hook
1486 precache_sound ("weapons/hook_impact.wav"); // hook
1489 if(autocvar_sv_precacheweapons)
1491 //precache weapon models/sounds
1494 while (wep <= WEP_LAST)
1496 weapon_action(wep, WR_PRECACHE);
1501 precache_model("models/elaser.mdl");
1502 precache_model("models/laser.mdl");
1503 precache_model("models/ebomb.mdl");
1506 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1508 if (!self.noise && self.music) // quake 3 uses the music field
1509 self.noise = self.music;
1511 // plays music for the level if there is any
1514 precache_sound (self.noise);
1515 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1520 // WARNING: this kills the trace globals
1521 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1522 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1524 #define INITPRIO_FIRST 0
1525 #define INITPRIO_GAMETYPE 0
1526 #define INITPRIO_GAMETYPE_FALLBACK 1
1527 #define INITPRIO_FINDTARGET 10
1528 #define INITPRIO_DROPTOFLOOR 20
1529 #define INITPRIO_SETLOCATION 90
1530 #define INITPRIO_LINKDOORS 91
1531 #define INITPRIO_LAST 99
1533 .void(void) initialize_entity;
1534 .float initialize_entity_order;
1535 .entity initialize_entity_next;
1536 entity initialize_entity_first;
1538 void make_safe_for_remove(entity e)
1540 if (e.initialize_entity)
1542 entity ent, prev = world;
1543 for (ent = initialize_entity_first; ent; )
1545 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1547 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1548 // skip it in linked list
1551 prev.initialize_entity_next = ent.initialize_entity_next;
1552 ent = prev.initialize_entity_next;
1556 initialize_entity_first = ent.initialize_entity_next;
1557 ent = initialize_entity_first;
1563 ent = ent.initialize_entity_next;
1569 void objerror(string s)
1571 make_safe_for_remove(self);
1572 builtin_objerror(s);
1575 .float remove_except_protected_forbidden;
1576 void remove_except_protected(entity e)
1578 if(e.remove_except_protected_forbidden)
1579 error("not allowed to remove this at this point");
1583 void remove_unsafely(entity e)
1585 if(e.classname == "spike")
1586 error("Removing spikes is forbidden (crylink bug), please report");
1590 void remove_safely(entity e)
1592 make_safe_for_remove(e);
1596 void InitializeEntity(entity e, void(void) func, float order)
1600 if (!e || e.initialize_entity)
1602 // make a proxy initializer entity
1606 e.classname = "initialize_entity";
1610 e.initialize_entity = func;
1611 e.initialize_entity_order = order;
1613 cur = initialize_entity_first;
1617 if (!cur || cur.initialize_entity_order > order)
1619 // insert between prev and cur
1621 prev.initialize_entity_next = e;
1623 initialize_entity_first = e;
1624 e.initialize_entity_next = cur;
1628 cur = cur.initialize_entity_next;
1631 void InitializeEntitiesRun()
1634 startoflist = initialize_entity_first;
1635 initialize_entity_first = world;
1636 remove = remove_except_protected;
1637 for (self = startoflist; self; self = self.initialize_entity_next)
1639 self.remove_except_protected_forbidden = 1;
1641 for (self = startoflist; self; )
1644 var void(void) func;
1645 e = self.initialize_entity_next;
1646 func = self.initialize_entity;
1647 self.initialize_entity_order = 0;
1648 self.initialize_entity = func_null;
1649 self.initialize_entity_next = world;
1650 self.remove_except_protected_forbidden = 0;
1651 if (self.classname == "initialize_entity")
1655 builtin_remove(self);
1658 //dprint("Delayed initialization: ", self.classname, "\n");
1664 backtrace(strcat("Null function in: ", self.classname, "\n"));
1668 remove = remove_unsafely;
1671 .float uncustomizeentityforclient_set;
1672 .void(void) uncustomizeentityforclient;
1673 void UncustomizeEntitiesRun()
1677 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1678 self.uncustomizeentityforclient();
1681 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1683 e.customizeentityforclient = customizer;
1684 e.uncustomizeentityforclient = uncustomizer;
1685 e.uncustomizeentityforclient_set = !!uncustomizer;
1689 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1692 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1696 if (e.classname == "")
1697 e.classname = "net_linked";
1699 if (e.model == "" || self.modelindex == 0)
1703 setmodel(e, "null");
1707 e.SendEntity = sendfunc;
1708 e.SendFlags = 0xFFFFFF;
1711 e.effects |= EF_NODEPTHTEST;
1715 e.nextthink = time + dt;
1716 e.think = SUB_Remove;
1720 void adaptor_think2touch()
1729 void adaptor_think2use()
1741 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1743 if not(self.flags & FL_ONGROUND) // if onground, we ARE touching something, but HITTYPE_SPLASH is to be networked if the damage causing projectile is not touching ANYTHING
1744 self.projectiledeathtype |= HITTYPE_SPLASH;
1745 adaptor_think2use();
1748 // deferred dropping
1749 void DropToFloor_Handler()
1751 builtin_droptofloor();
1752 self.dropped_origin = self.origin;
1757 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1762 float trace_hits_box_a0, trace_hits_box_a1;
1764 float trace_hits_box_1d(float end, float thmi, float thma)
1768 // just check if x is in range
1776 // do the trace with respect to x
1777 // 0 -> end has to stay in thmi -> thma
1778 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1779 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1780 if (trace_hits_box_a0 > trace_hits_box_a1)
1786 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1791 // now it is a trace from 0 to end
1793 trace_hits_box_a0 = 0;
1794 trace_hits_box_a1 = 1;
1796 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1798 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1800 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1806 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1808 return trace_hits_box(start, end, thmi - ma, thma - mi);
1811 float SUB_NoImpactCheck()
1813 // zero hitcontents = this is not the real impact, but either the
1814 // mirror-impact of something hitting the projectile instead of the
1815 // projectile hitting the something, or a touchareagrid one. Neither of
1816 // these stop the projectile from moving, so...
1817 if(trace_dphitcontents == 0)
1819 //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1820 dprint(sprintf(_("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Profectile will self-destruct. (edict: %d, classname: %s, origin: %s)\n"), num_for_edict(self), self.classname, vtos(self.origin)));
1823 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1825 if (other == world && self.size != '0 0 0')
1828 tic = self.velocity * sys_frametime;
1829 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1830 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1831 if (trace_fraction >= 1)
1833 dprint("Odd... did not hit...?\n");
1835 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1837 dprint("Detected and prevented the sky-grapple bug.\n");
1845 #define SUB_OwnerCheck() (other && (other == self.owner))
1847 void RemoveGrapplingHook(entity pl);
1848 void W_Crylink_Dequeue(entity e);
1849 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
1851 if(SUB_OwnerCheck())
1853 if(SUB_NoImpactCheck())
1855 if(self.classname == "grapplinghook")
1856 RemoveGrapplingHook(self.realowner);
1857 else if(self.classname == "spike")
1859 W_Crylink_Dequeue(self);
1866 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
1867 UpdateCSQCProjectile(self);
1870 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
1872 #define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
1873 #define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP))
1875 void URI_Get_Callback(float id, float status, string data)
1877 if(url_URI_Get_Callback(id, status, data))
1881 else if (id == URI_GET_DISCARD)
1885 else if (id >= URI_GET_CURL && id <= URI_GET_CURL_END)
1888 Curl_URI_Get_Callback(id, status, data);
1890 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1893 OnlineBanList_URI_Get_Callback(id, status, data);
1897 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1901 string uid2name(string myuid) {
1903 s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
1905 // FIXME remove this later after 0.6 release
1906 // convert old style broken records to correct style
1909 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
1912 db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
1913 db_put(ServerProgsDB, strcat("uid2name", myuid), "");
1918 s = "^1Unregistered Player";
1922 float race_readTime(string map, float pos)
1930 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
1933 string race_readUID(string map, float pos)
1941 return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
1944 float race_readPos(string map, float t) {
1946 for (i = 1; i <= RANKINGS_CNT; ++i)
1947 if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
1950 return 0; // pos is zero if unranked
1953 void race_writeTime(string map, float t, string myuid)
1962 newpos = race_readPos(map, t);
1964 float i, prevpos = 0;
1965 for(i = 1; i <= RANKINGS_CNT; ++i)
1967 if(race_readUID(map, i) == myuid)
1970 if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
1971 for (i = prevpos; i > newpos; --i) {
1972 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
1973 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
1975 } else { // player has no ranked record yet
1976 for (i = RANKINGS_CNT; i > newpos; --i) {
1977 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
1978 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
1982 // store new time itself
1983 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
1984 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
1987 string race_readName(string map, float pos)
1995 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
1998 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2001 vector start, org, delta, end, enddown, mstart;
2004 m = e.dphitcontentsmask;
2005 e.dphitcontentsmask = goodcontents | badcontents;
2008 delta = world.maxs - world.mins;
2012 for (i = 0; i < attempts; ++i)
2014 start_x = org_x + random() * delta_x;
2015 start_y = org_y + random() * delta_y;
2016 start_z = org_z + random() * delta_z;
2018 // rule 1: start inside world bounds, and outside
2019 // solid, and don't start from somewhere where you can
2020 // fall down to evil
2021 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2022 if (trace_fraction >= 1)
2024 if (trace_startsolid)
2026 if (trace_dphitcontents & badcontents)
2028 if (trace_dphitq3surfaceflags & badsurfaceflags)
2031 // rule 2: if we are too high, lower the point
2032 if (trace_fraction * delta_z > maxaboveground)
2033 start = trace_endpos + '0 0 1' * maxaboveground;
2034 enddown = trace_endpos;
2036 // rule 3: make sure we aren't outside the map. This only works
2037 // for somewhat well formed maps. A good rule of thumb is that
2038 // the map should have a convex outside hull.
2039 // these can be traceLINES as we already verified the starting box
2040 mstart = start + 0.5 * (e.mins + e.maxs);
2041 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2042 if (trace_fraction >= 1)
2044 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2045 if (trace_fraction >= 1)
2047 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2048 if (trace_fraction >= 1)
2050 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2051 if (trace_fraction >= 1)
2053 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2054 if (trace_fraction >= 1)
2057 // rule 4: we must "see" some spawnpoint
2058 for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
2059 if(checkpvs(mstart, sp))
2063 for(sp = world; (sp = findflags(sp, flags, FL_ITEM)); )
2064 if(checkpvs(mstart, sp))
2070 // find a random vector to "look at"
2071 end_x = org_x + random() * delta_x;
2072 end_y = org_y + random() * delta_y;
2073 end_z = org_z + random() * delta_z;
2074 end = start + normalize(end - start) * vlen(delta);
2076 // rule 4: start TO end must not be too short
2077 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2078 if (trace_startsolid)
2080 if (trace_fraction < minviewdistance / vlen(delta))
2083 // rule 5: don't want to look at sky
2084 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2087 // rule 6: we must not end up in trigger_hurt
2088 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2094 e.dphitcontentsmask = m;
2098 setorigin(e, start);
2099 e.angles = vectoangles(end - start);
2100 dprint("Needed ", ftos(i + 1), " attempts\n");
2107 float zcurveparticles_effectno;
2108 vector zcurveparticles_start;
2109 float zcurveparticles_spd;
2111 void endzcurveparticles()
2113 if(zcurveparticles_effectno)
2116 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2118 zcurveparticles_effectno = 0;
2121 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2123 spd = bound(0, floor(spd / 16), 32767);
2124 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2126 endzcurveparticles();
2127 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2128 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2129 WriteShort(MSG_BROADCAST, effectno);
2130 WriteCoord(MSG_BROADCAST, start_x);
2131 WriteCoord(MSG_BROADCAST, start_y);
2132 WriteCoord(MSG_BROADCAST, start_z);
2133 zcurveparticles_effectno = effectno;
2134 zcurveparticles_start = start;
2137 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2138 WriteCoord(MSG_BROADCAST, end_x);
2139 WriteCoord(MSG_BROADCAST, end_y);
2140 WriteCoord(MSG_BROADCAST, end_z);
2141 WriteCoord(MSG_BROADCAST, end_dz);
2142 zcurveparticles_spd = spd;
2145 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2148 vector vecxy, velxy;
2150 vecxy = end - start;
2155 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2157 endzcurveparticles();
2158 trailparticles(world, effectno, start, end);
2162 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2163 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2166 void write_recordmarker(entity pl, float tstart, float dt)
2168 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2170 // also write a marker into demo files for demotc-race-record-extractor to find
2173 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2174 " ", ftos(tstart), " ", ftos(dt), "\n"));
2177 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2190 if(allowcenter) // 2: allow center handedness
2203 if(allowcenter) // 2: allow center handedness
2219 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2224 if (autocvar_g_shootfromeye)
2228 if (autocvar_g_shootfromclient) { vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn); }
2229 else { vecs_y = 0; vecs_z -= 2; }
2237 else if (autocvar_g_shootfromcenter)
2242 else if ((s = autocvar_g_shootfromfixedorigin) != "")
2252 else if (autocvar_g_shootfromclient)
2254 vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn);
2259 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2261 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2265 void attach_sameorigin(entity e, entity to, string tag)
2267 vector org, t_forward, t_left, t_up, e_forward, e_up;
2270 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2271 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2272 t_forward = v_forward * tagscale;
2273 t_left = v_right * -tagscale;
2274 t_up = v_up * tagscale;
2276 e.origin_x = org * t_forward;
2277 e.origin_y = org * t_left;
2278 e.origin_z = org * t_up;
2280 // current forward and up directions
2281 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2282 e.angles = AnglesTransform_FromVAngles(e.angles);
2284 e.angles = AnglesTransform_FromAngles(e.angles);
2285 fixedmakevectors(e.angles);
2287 // untransform forward, up!
2288 e_forward_x = v_forward * t_forward;
2289 e_forward_y = v_forward * t_left;
2290 e_forward_z = v_forward * t_up;
2291 e_up_x = v_up * t_forward;
2292 e_up_y = v_up * t_left;
2293 e_up_z = v_up * t_up;
2295 e.angles = fixedvectoangles2(e_forward, e_up);
2296 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2297 e.angles = AnglesTransform_ToVAngles(e.angles);
2299 e.angles = AnglesTransform_ToAngles(e.angles);
2301 setattachment(e, to, tag);
2302 setorigin(e, e.origin);
2305 void detach_sameorigin(entity e)
2308 org = gettaginfo(e, 0);
2309 e.angles = fixedvectoangles2(v_forward, v_up);
2310 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2311 e.angles = AnglesTransform_ToVAngles(e.angles);
2313 e.angles = AnglesTransform_ToAngles(e.angles);
2315 setattachment(e, world, "");
2316 setorigin(e, e.origin);
2319 void follow_sameorigin(entity e, entity to)
2321 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2322 e.aiment = to; // make the hole follow bmodel
2323 e.punchangle = to.angles; // the original angles of bmodel
2324 e.view_ofs = e.origin - to.origin; // relative origin
2325 e.v_angle = e.angles - to.angles; // relative angles
2328 void unfollow_sameorigin(entity e)
2330 e.movetype = MOVETYPE_NONE;
2333 entity gettaginfo_relative_ent;
2334 vector gettaginfo_relative(entity e, float tag)
2336 if (!gettaginfo_relative_ent)
2338 gettaginfo_relative_ent = spawn();
2339 gettaginfo_relative_ent.effects = EF_NODRAW;
2341 gettaginfo_relative_ent.model = e.model;
2342 gettaginfo_relative_ent.modelindex = e.modelindex;
2343 gettaginfo_relative_ent.frame = e.frame;
2344 return gettaginfo(gettaginfo_relative_ent, tag);
2349 float modeleffect_SendEntity(entity to, float sf)
2352 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2355 if(self.velocity != '0 0 0')
2357 if(self.angles != '0 0 0')
2359 if(self.avelocity != '0 0 0')
2362 WriteByte(MSG_ENTITY, f);
2363 WriteShort(MSG_ENTITY, self.modelindex);
2364 WriteByte(MSG_ENTITY, self.skin);
2365 WriteByte(MSG_ENTITY, self.frame);
2366 WriteCoord(MSG_ENTITY, self.origin_x);
2367 WriteCoord(MSG_ENTITY, self.origin_y);
2368 WriteCoord(MSG_ENTITY, self.origin_z);
2371 WriteCoord(MSG_ENTITY, self.velocity_x);
2372 WriteCoord(MSG_ENTITY, self.velocity_y);
2373 WriteCoord(MSG_ENTITY, self.velocity_z);
2377 WriteCoord(MSG_ENTITY, self.angles_x);
2378 WriteCoord(MSG_ENTITY, self.angles_y);
2379 WriteCoord(MSG_ENTITY, self.angles_z);
2383 WriteCoord(MSG_ENTITY, self.avelocity_x);
2384 WriteCoord(MSG_ENTITY, self.avelocity_y);
2385 WriteCoord(MSG_ENTITY, self.avelocity_z);
2387 WriteShort(MSG_ENTITY, self.scale * 256.0);
2388 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2389 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2390 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2391 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2396 void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector ang, vector angv, float s0, float s2, float a, float t1, float t2)
2401 e.classname = "modeleffect";
2409 e.teleport_time = t1;
2413 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2417 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2420 sz = max(e.scale, e.scale2);
2421 setsize(e, e.mins * sz, e.maxs * sz);
2422 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2425 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2427 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2430 float randombit(float bits)
2432 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2441 for(f = 1; f <= bits; f *= 2)
2450 r = (r - 1) / (n - 1);
2457 float randombits(float bits, float k, float error_return)
2461 while(k > 0 && bits != r)
2463 r += randombit(bits - r);
2472 void randombit_test(float bits, float iter)
2476 print(ftos(randombit(bits)), "\n");
2481 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2483 if(halflifedist > 0)
2484 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2485 else if(halflifedist < 0)
2486 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2495 #define cvar_string_normal builtin_cvar_string
2496 #define cvar_normal builtin_cvar
2498 string cvar_string_normal(string n)
2500 if not(cvar_type(n) & 1)
2501 backtrace(strcat("Attempt to access undefined cvar: ", n));
2502 return builtin_cvar_string(n);
2505 float cvar_normal(string n)
2507 return stof(cvar_string_normal(n));
2510 #define cvar_set_normal builtin_cvar_set
2518 oself.think = SUB_Remove;
2519 oself.nextthink = time;
2525 Execute func() after time + fdelay.
2526 self when func is executed = self when defer is called
2528 void defer(float fdelay, void() func)
2535 e.think = defer_think;
2536 e.nextthink = time + fdelay;
2539 .string aiment_classname;
2540 .float aiment_deadflag;
2541 void SetMovetypeFollow(entity ent, entity e)
2543 // FIXME this may not be warpzone aware
2544 ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
2545 ent.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid - this means this cannot be teleported by warpzones any more! Instead, we must notice when our owner gets teleported.
2546 ent.aiment = e; // make the hole follow bmodel
2547 ent.punchangle = e.angles; // the original angles of bmodel
2548 ent.view_ofs = ent.origin - e.origin; // relative origin
2549 ent.v_angle = ent.angles - e.angles; // relative angles
2550 ent.aiment_classname = strzone(e.classname);
2551 ent.aiment_deadflag = e.deadflag;
2553 void UnsetMovetypeFollow(entity ent)
2555 ent.movetype = MOVETYPE_FLY;
2556 PROJECTILE_MAKETRIGGER(ent);
2559 float LostMovetypeFollow(entity ent)
2562 if(ent.movetype != MOVETYPE_FOLLOW)
2568 if(ent.aiment.classname != ent.aiment_classname)
2570 if(ent.aiment.deadflag != ent.aiment_deadflag)
2576 float isPushable(entity e)
2585 case "droppedweapon":
2586 case "keepawayball":
2587 case "nexball_basketball":
2588 case "nexball_football":
2590 case "bullet": // antilagged bullets can't hit this either
2593 if (e.projectiledeathtype)