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);
831 start_items |= IT_UNLIMITED_AMMO;
833 else if (g_minstagib)
835 g_pinata = 0; // incompatible
836 g_weapon_stay = 0; // incompatible
837 g_bloodloss = 0; // incompatible
839 start_armorvalue = 0;
840 WEPSET_COPY_AW(start_weapons, WEP_MINSTANEX);
841 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
842 start_items |= IT_UNLIMITED_SUPERWEAPONS;
844 if (g_minstagib_invis_alpha <= 0)
845 g_minstagib_invis_alpha = -1;
849 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
851 e = get_weaponinfo(i);
852 float w = want_weapon("g_start_weapon_", e, FALSE);
854 WEPSET_OR_AW(start_weapons, i);
856 WEPSET_OR_AW(start_weapons_default, i);
858 WEPSET_OR_AW(start_weapons_defaultmask, i);
862 if(!cvar("g_use_ammunition"))
863 start_items |= IT_UNLIMITED_AMMO;
865 if(cvar("g_nexball"))
866 start_items |= IT_UNLIMITED_SUPERWEAPONS; // FIXME BAD BAD BAD BAD HACK, NEXBALL SHOULDN'T ABUSE PORTO'S WEAPON SLOT
870 start_ammo_cells = cvar("g_minstagib_ammo_start");
871 start_ammo_fuel = cvar("g_start_ammo_fuel");
873 else if(start_items & IT_UNLIMITED_WEAPON_AMMO)
875 start_ammo_rockets = 999;
876 start_ammo_shells = 999;
877 start_ammo_cells = 999;
878 start_ammo_nails = 999;
879 start_ammo_fuel = 999;
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");
892 warmup_start_ammo_shells = start_ammo_shells;
893 warmup_start_ammo_nails = start_ammo_nails;
894 warmup_start_ammo_rockets = start_ammo_rockets;
895 warmup_start_ammo_cells = start_ammo_cells;
896 warmup_start_ammo_fuel = start_ammo_fuel;
897 warmup_start_health = start_health;
898 warmup_start_armorvalue = start_armorvalue;
899 WEPSET_COPY_AA(warmup_start_weapons, start_weapons);
900 WEPSET_COPY_AA(warmup_start_weapons_default, start_weapons_default);
901 WEPSET_COPY_AA(warmup_start_weapons_defaultmask, start_weapons_defaultmask);
903 if (!g_weaponarena && !g_minstagib && !g_ca)
905 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
906 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
907 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
908 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
909 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
910 warmup_start_health = cvar("g_warmup_start_health");
911 warmup_start_armorvalue = cvar("g_warmup_start_armor");
912 WEPSET_CLEAR_A(warmup_start_weapons);
913 WEPSET_CLEAR_A(warmup_start_weapons_default);
914 WEPSET_CLEAR_A(warmup_start_weapons_defaultmask);
915 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
917 e = get_weaponinfo(i);
918 float w = want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns"));
920 WEPSET_OR_AW(warmup_start_weapons, i);
922 WEPSET_OR_AW(warmup_start_weapons_default, i);
924 WEPSET_OR_AW(warmup_start_weapons_defaultmask, i);
930 start_items |= IT_JETPACK;
932 MUTATOR_CALLHOOK(SetStartItems);
934 if ((start_items & IT_JETPACK) || (g_grappling_hook && WEPSET_CONTAINS_AW(start_weapons, WEP_HOOK)))
936 g_grappling_hook = 0; // these two can't coexist, as they use the same button
937 start_items |= IT_FUEL_REGEN;
938 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
939 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
942 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
944 e = get_weaponinfo(i);
945 if(WEPSET_CONTAINS_AW(start_weapons, i) || WEPSET_CONTAINS_AW(warmup_start_weapons, i))
946 weapon_action(i, WR_PRECACHE);
949 start_ammo_shells = max(0, start_ammo_shells);
950 start_ammo_nails = max(0, start_ammo_nails);
951 start_ammo_cells = max(0, start_ammo_cells);
952 start_ammo_rockets = max(0, start_ammo_rockets);
953 start_ammo_fuel = max(0, start_ammo_fuel);
955 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
956 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
957 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
958 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
959 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
963 float g_bugrigs_planar_movement;
964 float g_bugrigs_planar_movement_car_jumping;
965 float g_bugrigs_reverse_spinning;
966 float g_bugrigs_reverse_speeding;
967 float g_bugrigs_reverse_stopping;
968 float g_bugrigs_air_steering;
969 float g_bugrigs_angle_smoothing;
970 float g_bugrigs_friction_floor;
971 float g_bugrigs_friction_brake;
972 float g_bugrigs_friction_air;
973 float g_bugrigs_accel;
974 float g_bugrigs_speed_ref;
975 float g_bugrigs_speed_pow;
976 float g_bugrigs_steer;
981 string GetGametype(); // g_world.qc
982 void readlevelcvars(void)
984 g_minstagib = cvar("g_minstagib");
986 // load ALL the mutators
987 if(cvar("g_dodging"))
988 MUTATOR_ADD(mutator_dodging);
989 if(cvar("g_spawn_near_teammate"))
990 MUTATOR_ADD(mutator_spawn_near_teammate);
991 if(cvar("g_physical_items"))
992 MUTATOR_ADD(mutator_physical_items);
993 if(cvar("g_touchexplode"))
994 MUTATOR_ADD(mutator_touchexplode);
997 if(cvar("g_invincible_projectiles"))
998 MUTATOR_ADD(mutator_invincibleprojectiles);
999 if(cvar("g_new_toys"))
1000 MUTATOR_ADD(mutator_new_toys);
1002 MUTATOR_ADD(mutator_nix);
1003 if(cvar("g_rocket_flying"))
1004 MUTATOR_ADD(mutator_rocketflying);
1005 if(cvar("g_vampire"))
1006 MUTATOR_ADD(mutator_vampire);
1007 if(cvar("g_superspectate"))
1008 MUTATOR_ADD(mutator_superspec);
1011 // is this a mutator? is this a mode?
1012 if(cvar("g_sandbox"))
1013 MUTATOR_ADD(sandbox);
1015 if(cvar("sv_allow_fullbright"))
1016 serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
1018 g_bugrigs = cvar("g_bugrigs");
1019 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1020 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1021 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1022 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1023 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1024 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1025 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1026 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1027 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1028 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1029 g_bugrigs_accel = cvar("g_bugrigs_accel");
1030 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1031 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1032 g_bugrigs_steer = cvar("g_bugrigs_steer");
1034 sv_clones = cvar("sv_clones");
1035 sv_foginterval = cvar("sv_foginterval");
1036 g_cloaked = cvar("g_cloaked");
1038 g_cloaked = 1; // always enable cloak in CTS
1039 g_jump_grunt = cvar("g_jump_grunt");
1040 g_footsteps = cvar("g_footsteps");
1041 g_grappling_hook = cvar("g_grappling_hook");
1042 g_jetpack = cvar("g_jetpack");
1043 g_midair = cvar("g_midair");
1044 g_norecoil = cvar("g_norecoil");
1045 g_bloodloss = cvar("g_bloodloss");
1046 sv_maxidle = cvar("sv_maxidle");
1047 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1048 sv_autotaunt = cvar("sv_autotaunt");
1049 sv_taunt = cvar("sv_taunt");
1051 inWarmupStage = cvar("g_warmup");
1052 g_warmup_limit = cvar("g_warmup_limit");
1053 g_warmup_allguns = cvar("g_warmup_allguns");
1054 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1056 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
1057 inWarmupStage = 0; // these modes cannot work together, sorry
1059 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1060 g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
1061 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1062 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1063 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1064 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1065 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1066 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1067 g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
1068 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1069 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1070 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1071 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1072 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1074 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1075 g_weaponratefactor = cvar("g_weaponratefactor");
1076 g_weapondamagefactor = cvar("g_weapondamagefactor");
1077 g_weaponforcefactor = cvar("g_weaponforcefactor");
1078 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1080 g_pickup_shells = cvar("g_pickup_shells");
1081 g_pickup_shells_max = cvar("g_pickup_shells_max");
1082 g_pickup_nails = cvar("g_pickup_nails");
1083 g_pickup_nails_max = cvar("g_pickup_nails_max");
1084 g_pickup_rockets = cvar("g_pickup_rockets");
1085 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1086 g_pickup_cells = cvar("g_pickup_cells");
1087 g_pickup_cells_max = cvar("g_pickup_cells_max");
1088 g_pickup_fuel = cvar("g_pickup_fuel");
1089 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1090 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1091 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1092 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1093 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1094 g_pickup_armormedium = cvar("g_pickup_armormedium");
1095 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1096 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1097 g_pickup_armorbig = cvar("g_pickup_armorbig");
1098 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1099 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1100 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1101 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1102 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1103 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1104 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1105 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1106 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1107 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1108 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1109 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1110 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1111 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1112 g_pickup_healthmega = cvar("g_pickup_healthmega");
1113 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1114 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1116 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1117 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1119 g_pinata = cvar("g_pinata");
1121 g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
1123 g_weapon_stay = cvar("g_weapon_stay");
1125 if not(inWarmupStage)
1126 game_starttime = time + cvar("g_start_delay");
1128 readplayerstartcvars();
1134 string precache_sound (string s) = #19;
1135 float precache_sound_index (string s) = #19;
1137 #define SND_VOLUME 1
1138 #define SND_ATTENUATION 2
1139 #define SND_LARGEENTITY 8
1140 #define SND_LARGESOUND 16
1142 float sound_allowed(float dest, entity e)
1144 // sounds from world may always pass
1147 if (e.classname == "body")
1149 else if (e.realowner && e.realowner != e)
1151 else if (e.owner && e.owner != e)
1156 // sounds to self may always pass
1157 if (dest == MSG_ONE)
1158 if (e == msg_entity)
1160 // sounds by players can be removed
1161 if (autocvar_bot_sound_monopoly)
1162 if (clienttype(e) == CLIENTTYPE_REAL)
1164 // anything else may pass
1168 #ifdef COMPAT_XON010_CHANNELS
1169 void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
1170 void sound(entity e, float chan, string samp, float vol, float atten)
1172 if (!sound_allowed(MSG_BROADCAST, e))
1174 builtin_sound(e, chan, samp, vol, atten);
1178 void sound(entity e, float chan, string samp, float vol, float atten)
1180 if (!sound_allowed(MSG_BROADCAST, e))
1182 sound7(e, chan, samp, vol, atten, 0, 0);
1186 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1190 if (!sound_allowed(dest, e))
1193 entno = num_for_edict(e);
1194 idx = precache_sound_index(samp);
1199 atten = floor(atten * 64);
1200 vol = floor(vol * 255);
1203 sflags |= SND_VOLUME;
1205 sflags |= SND_ATTENUATION;
1206 if (entno >= 8192 || chan < 0 || chan > 7)
1207 sflags |= SND_LARGEENTITY;
1209 sflags |= SND_LARGESOUND;
1211 WriteByte(dest, SVC_SOUND);
1212 WriteByte(dest, sflags);
1213 if (sflags & SND_VOLUME)
1214 WriteByte(dest, vol);
1215 if (sflags & SND_ATTENUATION)
1216 WriteByte(dest, atten);
1217 if (sflags & SND_LARGEENTITY)
1219 WriteShort(dest, entno);
1220 WriteByte(dest, chan);
1224 WriteShort(dest, entno * 8 + chan);
1226 if (sflags & SND_LARGESOUND)
1227 WriteShort(dest, idx);
1229 WriteByte(dest, idx);
1231 WriteCoord(dest, o_x);
1232 WriteCoord(dest, o_y);
1233 WriteCoord(dest, o_z);
1235 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1239 if (!sound_allowed(dest, e))
1242 o = e.origin + 0.5 * (e.mins + e.maxs);
1243 soundtoat(dest, e, o, chan, samp, vol, atten);
1245 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1247 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, atten);
1249 void stopsoundto(float dest, entity e, float chan)
1253 if (!sound_allowed(dest, e))
1256 entno = num_for_edict(e);
1258 if (entno >= 8192 || chan < 0 || chan > 7)
1261 idx = precache_sound_index("misc/null.wav");
1262 sflags = SND_LARGEENTITY;
1264 sflags |= SND_LARGESOUND;
1265 WriteByte(dest, SVC_SOUND);
1266 WriteByte(dest, sflags);
1267 WriteShort(dest, entno);
1268 WriteByte(dest, chan);
1269 if (sflags & SND_LARGESOUND)
1270 WriteShort(dest, idx);
1272 WriteByte(dest, idx);
1273 WriteCoord(dest, e.origin_x);
1274 WriteCoord(dest, e.origin_y);
1275 WriteCoord(dest, e.origin_z);
1279 WriteByte(dest, SVC_STOPSOUND);
1280 WriteShort(dest, entno * 8 + chan);
1283 void stopsound(entity e, float chan)
1285 if (!sound_allowed(MSG_BROADCAST, e))
1288 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1289 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1292 void play2(entity e, string filename)
1294 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1296 soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTN_NONE);
1299 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1301 float spamsound(entity e, float chan, string samp, float vol, float atten)
1303 if (!sound_allowed(MSG_BROADCAST, e))
1306 if (time > e.spamtime)
1309 sound(e, chan, samp, vol, atten);
1315 void play2team(float t, string filename)
1319 if (autocvar_bot_sound_monopoly)
1322 FOR_EACH_REALPLAYER(head)
1325 play2(head, filename);
1329 void play2all(string samp)
1331 if (autocvar_bot_sound_monopoly)
1334 sound(world, CH_INFO, samp, VOL_BASE, ATTN_NONE);
1337 void PrecachePlayerSounds(string f);
1338 void precache_playermodel(string m)
1340 float globhandle, i, n;
1343 if(substring(m, -9,5) == "_lod1")
1345 if(substring(m, -9,5) == "_lod2")
1348 f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
1351 f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
1355 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1358 n = search_getsize(globhandle);
1359 for (i = 0; i < n; ++i)
1361 //print(search_getfilename(globhandle, i), "\n");
1362 f = search_getfilename(globhandle, i);
1363 PrecachePlayerSounds(f);
1365 search_end(globhandle);
1367 void precache_all_playermodels(string pattern)
1369 float globhandle, i, n;
1372 globhandle = search_begin(pattern, TRUE, FALSE);
1375 n = search_getsize(globhandle);
1376 for (i = 0; i < n; ++i)
1378 //print(search_getfilename(globhandle, i), "\n");
1379 f = search_getfilename(globhandle, i);
1380 precache_playermodel(f);
1382 search_end(globhandle);
1387 // gamemode related things
1388 precache_model ("models/misc/chatbubble.spr");
1390 #ifdef TTURRETS_ENABLED
1391 if (autocvar_g_turrets)
1395 // Precache all player models if desired
1396 if (autocvar_sv_precacheplayermodels)
1398 PrecachePlayerSounds("sound/player/default.sounds");
1399 precache_all_playermodels("models/player/*.zym");
1400 precache_all_playermodels("models/player/*.dpm");
1401 precache_all_playermodels("models/player/*.md3");
1402 precache_all_playermodels("models/player/*.psk");
1403 precache_all_playermodels("models/player/*.iqm");
1406 if (autocvar_sv_defaultcharacter)
1409 s = autocvar_sv_defaultplayermodel_red;
1411 precache_playermodel(s);
1412 s = autocvar_sv_defaultplayermodel_blue;
1414 precache_playermodel(s);
1415 s = autocvar_sv_defaultplayermodel_yellow;
1417 precache_playermodel(s);
1418 s = autocvar_sv_defaultplayermodel_pink;
1420 precache_playermodel(s);
1421 s = autocvar_sv_defaultplayermodel;
1423 precache_playermodel(s);
1428 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1429 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1432 // gore and miscellaneous sounds
1433 //precache_sound ("misc/h2ohit.wav");
1434 precache_model ("models/hook.md3");
1435 precache_sound ("misc/armorimpact.wav");
1436 precache_sound ("misc/bodyimpact1.wav");
1437 precache_sound ("misc/bodyimpact2.wav");
1438 precache_sound ("misc/gib.wav");
1439 precache_sound ("misc/gib_splat01.wav");
1440 precache_sound ("misc/gib_splat02.wav");
1441 precache_sound ("misc/gib_splat03.wav");
1442 precache_sound ("misc/gib_splat04.wav");
1443 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1444 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1445 precache_sound ("misc/null.wav");
1446 precache_sound ("misc/spawn.wav");
1447 precache_sound ("misc/talk.wav");
1448 precache_sound ("misc/teleport.wav");
1449 precache_sound ("misc/poweroff.wav");
1450 precache_sound ("player/lava.wav");
1451 precache_sound ("player/slime.wav");
1453 precache_model ("models/sprites/0.spr32");
1454 precache_model ("models/sprites/1.spr32");
1455 precache_model ("models/sprites/2.spr32");
1456 precache_model ("models/sprites/3.spr32");
1457 precache_model ("models/sprites/4.spr32");
1458 precache_model ("models/sprites/5.spr32");
1459 precache_model ("models/sprites/6.spr32");
1460 precache_model ("models/sprites/7.spr32");
1461 precache_model ("models/sprites/8.spr32");
1462 precache_model ("models/sprites/9.spr32");
1463 precache_model ("models/sprites/10.spr32");
1465 // common weapon precaches
1466 precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound here
1467 precache_sound ("weapons/weapon_switch.wav");
1468 precache_sound ("weapons/weaponpickup.wav");
1469 precache_sound ("weapons/unavailable.wav");
1470 precache_sound ("weapons/dryfire.wav");
1471 if (g_grappling_hook)
1473 precache_sound ("weapons/hook_fire.wav"); // hook
1474 precache_sound ("weapons/hook_impact.wav"); // hook
1477 if(autocvar_sv_precacheweapons)
1479 //precache weapon models/sounds
1482 while (wep <= WEP_LAST)
1484 weapon_action(wep, WR_PRECACHE);
1489 precache_model("models/elaser.mdl");
1490 precache_model("models/laser.mdl");
1491 precache_model("models/ebomb.mdl");
1494 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1496 if (!self.noise && self.music) // quake 3 uses the music field
1497 self.noise = self.music;
1499 // plays music for the level if there is any
1502 precache_sound (self.noise);
1503 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1508 // WARNING: this kills the trace globals
1509 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1510 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1512 #define INITPRIO_FIRST 0
1513 #define INITPRIO_GAMETYPE 0
1514 #define INITPRIO_GAMETYPE_FALLBACK 1
1515 #define INITPRIO_FINDTARGET 10
1516 #define INITPRIO_DROPTOFLOOR 20
1517 #define INITPRIO_SETLOCATION 90
1518 #define INITPRIO_LINKDOORS 91
1519 #define INITPRIO_LAST 99
1521 .void(void) initialize_entity;
1522 .float initialize_entity_order;
1523 .entity initialize_entity_next;
1524 entity initialize_entity_first;
1526 void make_safe_for_remove(entity e)
1528 if (e.initialize_entity)
1530 entity ent, prev = world;
1531 for (ent = initialize_entity_first; ent; )
1533 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1535 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1536 // skip it in linked list
1539 prev.initialize_entity_next = ent.initialize_entity_next;
1540 ent = prev.initialize_entity_next;
1544 initialize_entity_first = ent.initialize_entity_next;
1545 ent = initialize_entity_first;
1551 ent = ent.initialize_entity_next;
1557 void objerror(string s)
1559 make_safe_for_remove(self);
1560 builtin_objerror(s);
1563 .float remove_except_protected_forbidden;
1564 void remove_except_protected(entity e)
1566 if(e.remove_except_protected_forbidden)
1567 error("not allowed to remove this at this point");
1571 void remove_unsafely(entity e)
1573 if(e.classname == "spike")
1574 error("Removing spikes is forbidden (crylink bug), please report");
1578 void remove_safely(entity e)
1580 make_safe_for_remove(e);
1584 void InitializeEntity(entity e, void(void) func, float order)
1588 if (!e || e.initialize_entity)
1590 // make a proxy initializer entity
1594 e.classname = "initialize_entity";
1598 e.initialize_entity = func;
1599 e.initialize_entity_order = order;
1601 cur = initialize_entity_first;
1605 if (!cur || cur.initialize_entity_order > order)
1607 // insert between prev and cur
1609 prev.initialize_entity_next = e;
1611 initialize_entity_first = e;
1612 e.initialize_entity_next = cur;
1616 cur = cur.initialize_entity_next;
1619 void InitializeEntitiesRun()
1622 startoflist = initialize_entity_first;
1623 initialize_entity_first = world;
1624 remove = remove_except_protected;
1625 for (self = startoflist; self; self = self.initialize_entity_next)
1627 self.remove_except_protected_forbidden = 1;
1629 for (self = startoflist; self; )
1632 var void(void) func;
1633 e = self.initialize_entity_next;
1634 func = self.initialize_entity;
1635 self.initialize_entity_order = 0;
1636 self.initialize_entity = func_null;
1637 self.initialize_entity_next = world;
1638 self.remove_except_protected_forbidden = 0;
1639 if (self.classname == "initialize_entity")
1643 builtin_remove(self);
1646 //dprint("Delayed initialization: ", self.classname, "\n");
1652 backtrace(strcat("Null function in: ", self.classname, "\n"));
1656 remove = remove_unsafely;
1659 .float uncustomizeentityforclient_set;
1660 .void(void) uncustomizeentityforclient;
1661 void UncustomizeEntitiesRun()
1665 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1666 self.uncustomizeentityforclient();
1669 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1671 e.customizeentityforclient = customizer;
1672 e.uncustomizeentityforclient = uncustomizer;
1673 e.uncustomizeentityforclient_set = !!uncustomizer;
1677 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1680 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1684 if (e.classname == "")
1685 e.classname = "net_linked";
1687 if (e.model == "" || self.modelindex == 0)
1691 setmodel(e, "null");
1695 e.SendEntity = sendfunc;
1696 e.SendFlags = 0xFFFFFF;
1699 e.effects |= EF_NODEPTHTEST;
1703 e.nextthink = time + dt;
1704 e.think = SUB_Remove;
1708 void adaptor_think2touch()
1717 void adaptor_think2use()
1729 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1731 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
1732 self.projectiledeathtype |= HITTYPE_SPLASH;
1733 adaptor_think2use();
1736 // deferred dropping
1737 void DropToFloor_Handler()
1739 builtin_droptofloor();
1740 self.dropped_origin = self.origin;
1745 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1750 float trace_hits_box_a0, trace_hits_box_a1;
1752 float trace_hits_box_1d(float end, float thmi, float thma)
1756 // just check if x is in range
1764 // do the trace with respect to x
1765 // 0 -> end has to stay in thmi -> thma
1766 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1767 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1768 if (trace_hits_box_a0 > trace_hits_box_a1)
1774 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1779 // now it is a trace from 0 to end
1781 trace_hits_box_a0 = 0;
1782 trace_hits_box_a1 = 1;
1784 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1786 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1788 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1794 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1796 return trace_hits_box(start, end, thmi - ma, thma - mi);
1799 float SUB_NoImpactCheck()
1801 // zero hitcontents = this is not the real impact, but either the
1802 // mirror-impact of something hitting the projectile instead of the
1803 // projectile hitting the something, or a touchareagrid one. Neither of
1804 // these stop the projectile from moving, so...
1805 if(trace_dphitcontents == 0)
1807 //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1808 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)));
1811 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1813 if (other == world && self.size != '0 0 0')
1816 tic = self.velocity * sys_frametime;
1817 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1818 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1819 if (trace_fraction >= 1)
1821 dprint("Odd... did not hit...?\n");
1823 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1825 dprint("Detected and prevented the sky-grapple bug.\n");
1833 #define SUB_OwnerCheck() (other && (other == self.owner))
1835 void RemoveGrapplingHook(entity pl);
1836 void W_Crylink_Dequeue(entity e);
1837 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
1839 if(SUB_OwnerCheck())
1841 if(SUB_NoImpactCheck())
1843 if(self.classname == "grapplinghook")
1844 RemoveGrapplingHook(self.realowner);
1845 else if(self.classname == "spike")
1847 W_Crylink_Dequeue(self);
1854 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
1855 UpdateCSQCProjectile(self);
1858 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
1860 #define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
1861 #define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP))
1863 void URI_Get_Callback(float id, float status, string data)
1865 if(url_URI_Get_Callback(id, status, data))
1869 else if (id == URI_GET_DISCARD)
1873 else if (id >= URI_GET_CURL && id <= URI_GET_CURL_END)
1876 Curl_URI_Get_Callback(id, status, data);
1878 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1881 OnlineBanList_URI_Get_Callback(id, status, data);
1885 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1889 string uid2name(string myuid) {
1891 s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
1893 // FIXME remove this later after 0.6 release
1894 // convert old style broken records to correct style
1897 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
1900 db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
1901 db_put(ServerProgsDB, strcat("uid2name", myuid), "");
1906 s = "^1Unregistered Player";
1910 float race_readTime(string map, float pos)
1918 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
1921 string race_readUID(string map, float pos)
1929 return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
1932 float race_readPos(string map, float t) {
1934 for (i = 1; i <= RANKINGS_CNT; ++i)
1935 if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
1938 return 0; // pos is zero if unranked
1941 void race_writeTime(string map, float t, string myuid)
1950 newpos = race_readPos(map, t);
1952 float i, prevpos = 0;
1953 for(i = 1; i <= RANKINGS_CNT; ++i)
1955 if(race_readUID(map, i) == myuid)
1958 if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
1959 for (i = prevpos; i > newpos; --i) {
1960 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
1961 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
1963 } else { // player has no ranked record yet
1964 for (i = RANKINGS_CNT; i > newpos; --i) {
1965 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
1966 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
1970 // store new time itself
1971 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
1972 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
1975 string race_readName(string map, float pos)
1983 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
1986 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
1989 vector start, org, delta, end, enddown, mstart;
1992 m = e.dphitcontentsmask;
1993 e.dphitcontentsmask = goodcontents | badcontents;
1996 delta = world.maxs - world.mins;
2000 for (i = 0; i < attempts; ++i)
2002 start_x = org_x + random() * delta_x;
2003 start_y = org_y + random() * delta_y;
2004 start_z = org_z + random() * delta_z;
2006 // rule 1: start inside world bounds, and outside
2007 // solid, and don't start from somewhere where you can
2008 // fall down to evil
2009 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2010 if (trace_fraction >= 1)
2012 if (trace_startsolid)
2014 if (trace_dphitcontents & badcontents)
2016 if (trace_dphitq3surfaceflags & badsurfaceflags)
2019 // rule 2: if we are too high, lower the point
2020 if (trace_fraction * delta_z > maxaboveground)
2021 start = trace_endpos + '0 0 1' * maxaboveground;
2022 enddown = trace_endpos;
2024 // rule 3: make sure we aren't outside the map. This only works
2025 // for somewhat well formed maps. A good rule of thumb is that
2026 // the map should have a convex outside hull.
2027 // these can be traceLINES as we already verified the starting box
2028 mstart = start + 0.5 * (e.mins + e.maxs);
2029 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2030 if (trace_fraction >= 1)
2032 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2033 if (trace_fraction >= 1)
2035 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2036 if (trace_fraction >= 1)
2038 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2039 if (trace_fraction >= 1)
2041 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2042 if (trace_fraction >= 1)
2045 // rule 4: we must "see" some spawnpoint
2046 for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
2047 if(checkpvs(mstart, sp))
2051 for(sp = world; (sp = findflags(sp, flags, FL_ITEM)); )
2052 if(checkpvs(mstart, sp))
2058 // find a random vector to "look at"
2059 end_x = org_x + random() * delta_x;
2060 end_y = org_y + random() * delta_y;
2061 end_z = org_z + random() * delta_z;
2062 end = start + normalize(end - start) * vlen(delta);
2064 // rule 4: start TO end must not be too short
2065 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2066 if (trace_startsolid)
2068 if (trace_fraction < minviewdistance / vlen(delta))
2071 // rule 5: don't want to look at sky
2072 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2075 // rule 6: we must not end up in trigger_hurt
2076 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2082 e.dphitcontentsmask = m;
2086 setorigin(e, start);
2087 e.angles = vectoangles(end - start);
2088 dprint("Needed ", ftos(i + 1), " attempts\n");
2095 float zcurveparticles_effectno;
2096 vector zcurveparticles_start;
2097 float zcurveparticles_spd;
2099 void endzcurveparticles()
2101 if(zcurveparticles_effectno)
2104 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2106 zcurveparticles_effectno = 0;
2109 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2111 spd = bound(0, floor(spd / 16), 32767);
2112 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2114 endzcurveparticles();
2115 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2116 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2117 WriteShort(MSG_BROADCAST, effectno);
2118 WriteCoord(MSG_BROADCAST, start_x);
2119 WriteCoord(MSG_BROADCAST, start_y);
2120 WriteCoord(MSG_BROADCAST, start_z);
2121 zcurveparticles_effectno = effectno;
2122 zcurveparticles_start = start;
2125 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2126 WriteCoord(MSG_BROADCAST, end_x);
2127 WriteCoord(MSG_BROADCAST, end_y);
2128 WriteCoord(MSG_BROADCAST, end_z);
2129 WriteCoord(MSG_BROADCAST, end_dz);
2130 zcurveparticles_spd = spd;
2133 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2136 vector vecxy, velxy;
2138 vecxy = end - start;
2143 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2145 endzcurveparticles();
2146 trailparticles(world, effectno, start, end);
2150 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2151 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2154 void write_recordmarker(entity pl, float tstart, float dt)
2156 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2158 // also write a marker into demo files for demotc-race-record-extractor to find
2161 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2162 " ", ftos(tstart), " ", ftos(dt), "\n"));
2165 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2178 if(allowcenter) // 2: allow center handedness
2191 if(allowcenter) // 2: allow center handedness
2207 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2212 if (autocvar_g_shootfromeye)
2216 if (autocvar_g_shootfromclient) { vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn); }
2217 else { vecs_y = 0; vecs_z -= 2; }
2225 else if (autocvar_g_shootfromcenter)
2230 else if ((s = autocvar_g_shootfromfixedorigin) != "")
2240 else if (autocvar_g_shootfromclient)
2242 vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn);
2247 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2249 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2253 void attach_sameorigin(entity e, entity to, string tag)
2255 vector org, t_forward, t_left, t_up, e_forward, e_up;
2258 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2259 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2260 t_forward = v_forward * tagscale;
2261 t_left = v_right * -tagscale;
2262 t_up = v_up * tagscale;
2264 e.origin_x = org * t_forward;
2265 e.origin_y = org * t_left;
2266 e.origin_z = org * t_up;
2268 // current forward and up directions
2269 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2270 e.angles = AnglesTransform_FromVAngles(e.angles);
2272 e.angles = AnglesTransform_FromAngles(e.angles);
2273 fixedmakevectors(e.angles);
2275 // untransform forward, up!
2276 e_forward_x = v_forward * t_forward;
2277 e_forward_y = v_forward * t_left;
2278 e_forward_z = v_forward * t_up;
2279 e_up_x = v_up * t_forward;
2280 e_up_y = v_up * t_left;
2281 e_up_z = v_up * t_up;
2283 e.angles = fixedvectoangles2(e_forward, e_up);
2284 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2285 e.angles = AnglesTransform_ToVAngles(e.angles);
2287 e.angles = AnglesTransform_ToAngles(e.angles);
2289 setattachment(e, to, tag);
2290 setorigin(e, e.origin);
2293 void detach_sameorigin(entity e)
2296 org = gettaginfo(e, 0);
2297 e.angles = fixedvectoangles2(v_forward, v_up);
2298 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2299 e.angles = AnglesTransform_ToVAngles(e.angles);
2301 e.angles = AnglesTransform_ToAngles(e.angles);
2303 setattachment(e, world, "");
2304 setorigin(e, e.origin);
2307 void follow_sameorigin(entity e, entity to)
2309 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2310 e.aiment = to; // make the hole follow bmodel
2311 e.punchangle = to.angles; // the original angles of bmodel
2312 e.view_ofs = e.origin - to.origin; // relative origin
2313 e.v_angle = e.angles - to.angles; // relative angles
2316 void unfollow_sameorigin(entity e)
2318 e.movetype = MOVETYPE_NONE;
2321 entity gettaginfo_relative_ent;
2322 vector gettaginfo_relative(entity e, float tag)
2324 if (!gettaginfo_relative_ent)
2326 gettaginfo_relative_ent = spawn();
2327 gettaginfo_relative_ent.effects = EF_NODRAW;
2329 gettaginfo_relative_ent.model = e.model;
2330 gettaginfo_relative_ent.modelindex = e.modelindex;
2331 gettaginfo_relative_ent.frame = e.frame;
2332 return gettaginfo(gettaginfo_relative_ent, tag);
2337 float modeleffect_SendEntity(entity to, float sf)
2340 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2343 if(self.velocity != '0 0 0')
2345 if(self.angles != '0 0 0')
2347 if(self.avelocity != '0 0 0')
2350 WriteByte(MSG_ENTITY, f);
2351 WriteShort(MSG_ENTITY, self.modelindex);
2352 WriteByte(MSG_ENTITY, self.skin);
2353 WriteByte(MSG_ENTITY, self.frame);
2354 WriteCoord(MSG_ENTITY, self.origin_x);
2355 WriteCoord(MSG_ENTITY, self.origin_y);
2356 WriteCoord(MSG_ENTITY, self.origin_z);
2359 WriteCoord(MSG_ENTITY, self.velocity_x);
2360 WriteCoord(MSG_ENTITY, self.velocity_y);
2361 WriteCoord(MSG_ENTITY, self.velocity_z);
2365 WriteCoord(MSG_ENTITY, self.angles_x);
2366 WriteCoord(MSG_ENTITY, self.angles_y);
2367 WriteCoord(MSG_ENTITY, self.angles_z);
2371 WriteCoord(MSG_ENTITY, self.avelocity_x);
2372 WriteCoord(MSG_ENTITY, self.avelocity_y);
2373 WriteCoord(MSG_ENTITY, self.avelocity_z);
2375 WriteShort(MSG_ENTITY, self.scale * 256.0);
2376 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2377 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2378 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2379 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2384 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)
2389 e.classname = "modeleffect";
2397 e.teleport_time = t1;
2401 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2405 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2408 sz = max(e.scale, e.scale2);
2409 setsize(e, e.mins * sz, e.maxs * sz);
2410 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2413 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2415 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2418 float randombit(float bits)
2420 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2429 for(f = 1; f <= bits; f *= 2)
2438 r = (r - 1) / (n - 1);
2445 float randombits(float bits, float k, float error_return)
2449 while(k > 0 && bits != r)
2451 r += randombit(bits - r);
2460 void randombit_test(float bits, float iter)
2464 print(ftos(randombit(bits)), "\n");
2469 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2471 if(halflifedist > 0)
2472 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2473 else if(halflifedist < 0)
2474 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2483 #define cvar_string_normal builtin_cvar_string
2484 #define cvar_normal builtin_cvar
2486 string cvar_string_normal(string n)
2488 if not(cvar_type(n) & 1)
2489 backtrace(strcat("Attempt to access undefined cvar: ", n));
2490 return builtin_cvar_string(n);
2493 float cvar_normal(string n)
2495 return stof(cvar_string_normal(n));
2498 #define cvar_set_normal builtin_cvar_set
2506 oself.think = SUB_Remove;
2507 oself.nextthink = time;
2513 Execute func() after time + fdelay.
2514 self when func is executed = self when defer is called
2516 void defer(float fdelay, void() func)
2523 e.think = defer_think;
2524 e.nextthink = time + fdelay;
2527 .string aiment_classname;
2528 .float aiment_deadflag;
2529 void SetMovetypeFollow(entity ent, entity e)
2531 // FIXME this may not be warpzone aware
2532 ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
2533 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.
2534 ent.aiment = e; // make the hole follow bmodel
2535 ent.punchangle = e.angles; // the original angles of bmodel
2536 ent.view_ofs = ent.origin - e.origin; // relative origin
2537 ent.v_angle = ent.angles - e.angles; // relative angles
2538 ent.aiment_classname = strzone(e.classname);
2539 ent.aiment_deadflag = e.deadflag;
2541 void UnsetMovetypeFollow(entity ent)
2543 ent.movetype = MOVETYPE_FLY;
2544 PROJECTILE_MAKETRIGGER(ent);
2547 float LostMovetypeFollow(entity ent)
2550 if(ent.movetype != MOVETYPE_FOLLOW)
2556 if(ent.aiment.classname != ent.aiment_classname)
2558 if(ent.aiment.deadflag != ent.aiment_deadflag)
2564 float isPushable(entity e)
2573 case "droppedweapon":
2574 case "keepawayball":
2575 case "nexball_basketball":
2576 case "nexball_football":
2578 case "bullet": // antilagged bullets can't hit this either
2581 if (e.projectiledeathtype)