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 FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; )
104 #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
106 // copies a string to a tempstring (so one can strunzone it)
107 string strcat1(string s) = #115; // FRIK_FILE
112 void GameLogEcho(string s)
117 if (autocvar_sv_eventlog_files)
122 matches = autocvar_sv_eventlog_files_counter + 1;
123 cvar_set("sv_eventlog_files_counter", ftos(matches));
126 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
127 fn = strcat(autocvar_sv_eventlog_files_nameprefix, fn, autocvar_sv_eventlog_files_namesuffix);
128 logfile = fopen(fn, FILE_APPEND);
129 fputs(logfile, ":logversion:3\n");
133 if (autocvar_sv_eventlog_files_timestamps)
134 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
136 fputs(logfile, strcat(s, "\n"));
139 if (autocvar_sv_eventlog_console)
148 // will be opened later
153 if (logfile_open && logfile >= 0)
160 float spawnpoint_nag;
161 void relocate_spawnpoint()
163 // nudge off the floor
164 setorigin(self, self.origin + '0 0 1');
166 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
167 if (trace_startsolid)
173 if (!move_out_of_solid(self))
174 objerror("could not get out of solid at all!");
175 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
176 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
177 print(" ", ftos(self.origin_y - o_y));
178 print(" ", ftos(self.origin_z - o_z), "'\n");
179 if (autocvar_g_spawnpoints_auto_move_out_of_solid)
182 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
188 self.mins = self.maxs = '0 0 0';
189 objerror("player spawn point in solid, mapper sucks!\n");
194 self.use = spawnpoint_use;
195 self.team_saved = self.team;
199 if (have_team_spawns != 0)
201 have_team_spawns = 1;
202 have_team_spawns_forteam[self.team] = 1;
204 if (autocvar_r_showbboxes)
206 // show where spawnpoints point at too
207 makevectors(self.angles);
210 e.classname = "info_player_foo";
211 setorigin(e, self.origin + v_forward * 24);
212 setsize(e, '-8 -8 -8', '8 8 8');
213 e.solid = SOLID_TRIGGER;
217 #define strstr strstrofs
219 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
220 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
221 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
222 // BE CONSTANT OR strzoneD!
223 float strstr(string haystack, string needle, float offset)
227 len = strlen(needle);
228 endpos = strlen(haystack) - len;
229 while(offset <= endpos)
231 found = substring(haystack, offset, len);
240 float NUM_NEAREST_ENTITIES = 4;
241 entity nearest_entity[NUM_NEAREST_ENTITIES];
242 float nearest_length[NUM_NEAREST_ENTITIES];
243 entity findnearest(vector point, .string field, string value, vector axismod)
254 localhead = find(world, field, value);
257 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
258 dist = localhead.oldorigin;
260 dist = localhead.origin;
262 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
265 for (i = 0; i < num_nearest; ++i)
267 if (len < nearest_length[i])
271 // now i tells us where to insert at
272 // INSERTION SORT! YOU'VE SEEN IT! RUN!
273 if (i < NUM_NEAREST_ENTITIES)
275 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
277 nearest_length[j + 1] = nearest_length[j];
278 nearest_entity[j + 1] = nearest_entity[j];
280 nearest_length[i] = len;
281 nearest_entity[i] = localhead;
282 if (num_nearest < NUM_NEAREST_ENTITIES)
283 num_nearest = num_nearest + 1;
286 localhead = find(localhead, field, value);
289 // now use the first one from our list that we can see
290 for (i = 0; i < num_nearest; ++i)
292 traceline(point, nearest_entity[i].origin, TRUE, world);
293 if (trace_fraction == 1)
297 dprint("Nearest point (");
298 dprint(nearest_entity[0].netname);
299 dprint(") is not visible, using a visible one.\n");
301 return nearest_entity[i];
305 if (num_nearest == 0)
308 dprint("Not seeing any location point, using nearest as fallback.\n");
310 dprint("Candidates were: ");
311 for(j = 0; j < num_nearest; ++j)
315 dprint(nearest_entity[j].netname);
320 return nearest_entity[0];
323 void spawnfunc_target_location()
325 self.classname = "target_location";
326 // location name in netname
327 // eventually support: count, teamgame selectors, line of sight?
330 void spawnfunc_info_location()
332 self.classname = "target_location";
333 self.message = self.netname;
336 string NearestLocation(vector p)
341 loc = findnearest(p, classname, "target_location", '1 1 1');
348 loc = findnearest(p, target, "###item###", '1 1 4');
355 string formatmessage(string msg)
366 WarpZone_crosshair_trace(self);
367 cursor = trace_endpos;
368 cursor_ent = trace_ent;
372 break; // too many replacements
375 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
376 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
389 replacement = substring(msg, p, 2);
390 escape = substring(msg, p + 1, 1);
394 else if (escape == "\\")
396 else if (escape == "n")
398 else if (escape == "a")
399 replacement = ftos(floor(self.armorvalue));
400 else if (escape == "h")
401 replacement = ftos(floor(self.health));
402 else if (escape == "l")
403 replacement = NearestLocation(self.origin);
404 else if (escape == "y")
405 replacement = NearestLocation(cursor);
406 else if (escape == "d")
407 replacement = NearestLocation(self.death_origin);
408 else if (escape == "w") {
412 wep = self.switchweapon;
415 replacement = W_Name(wep);
416 } else if (escape == "W") {
417 if (self.items & IT_SHELLS) replacement = "shells";
418 else if (self.items & IT_NAILS) replacement = "bullets";
419 else if (self.items & IT_ROCKETS) replacement = "rockets";
420 else if (self.items & IT_CELLS) replacement = "cells";
421 else replacement = "batteries"; // ;)
422 } else if (escape == "x") {
423 replacement = cursor_ent.netname;
424 if (replacement == "" || !cursor_ent)
425 replacement = "nothing";
426 } else if (escape == "s")
427 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
428 else if (escape == "S")
429 replacement = ftos(vlen(self.velocity));
431 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
432 p = p + strlen(replacement);
437 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
438 return (value == 0) ? FALSE : TRUE;
447 >0: receives a cvar from name=argv(f) value=argv(f+1)
449 void GetCvars_handleString(string thisname, float f, .string field, string name)
454 strunzone(self.field);
455 self.field = string_null;
459 if (thisname == name)
462 strunzone(self.field);
463 self.field = strzone(argv(f + 1));
467 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
469 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
471 GetCvars_handleString(thisname, f, field, name);
472 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
473 if (thisname == name)
476 s = func(strcat1(self.field));
479 strunzone(self.field);
480 self.field = strzone(s);
484 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
491 if (thisname == name)
492 self.field = stof(argv(f + 1));
495 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
497 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
504 if (thisname == name)
508 self.field = stof(argv(f + 1));
517 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
520 float w_getbestweapon(entity e);
521 string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(string wo)
524 o = W_FixWeaponOrder_ForceComplete(wo);
525 if(self.weaponorder_byimpulse)
527 strunzone(self.weaponorder_byimpulse);
528 self.weaponorder_byimpulse = string_null;
530 self.weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
533 void GetCvars(float f)
535 string s = string_null;
538 s = strcat1(argv(f));
543 MUTATOR_CALLHOOK(GetCvars);
545 Notification_GetCvars();
547 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
548 GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
549 GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
550 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
551 GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
552 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
553 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
554 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
555 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
556 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
557 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
558 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
559 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
560 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
561 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
562 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
563 GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode");
564 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
565 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
566 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
567 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
568 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
569 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
571 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
572 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
574 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
575 GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
576 GetCvars_handleFloat(s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
577 GetCvars_handleFloat(s, f, cvar_cl_movement_track_canjump, "cl_movement_track_canjump");
578 GetCvars_handleFloat(s, f, cvar_cl_newusekeysupported, "cl_newusekeysupported");
580 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
583 if (s == "cl_weaponpriority")
584 self.switchweapon = w_getbestweapon(self);
585 if (s == "cl_allow_uidtracking")
586 PlayerStats_AddPlayer(self);
590 // decolorizes and team colors the player name when needed
591 string playername(entity p)
594 if (teamplay && !intermission_running && p.classname == "player")
596 t = Team_ColorCode(p.team);
597 return strcat(t, strdecolorize(p.netname));
603 vector randompos(vector m1, vector m2)
607 v_x = m2_x * random() + m1_x;
608 v_y = m2_y * random() + m1_y;
609 v_z = m2_z * random() + m1_z;
613 //#NO AUTOCVARS START
615 float g_pickup_shells;
616 float g_pickup_shells_max;
617 float g_pickup_nails;
618 float g_pickup_nails_max;
619 float g_pickup_rockets;
620 float g_pickup_rockets_max;
621 float g_pickup_cells;
622 float g_pickup_cells_max;
624 float g_pickup_fuel_jetpack;
625 float g_pickup_fuel_max;
626 float g_pickup_armorsmall;
627 float g_pickup_armorsmall_max;
628 float g_pickup_armorsmall_anyway;
629 float g_pickup_armormedium;
630 float g_pickup_armormedium_max;
631 float g_pickup_armormedium_anyway;
632 float g_pickup_armorbig;
633 float g_pickup_armorbig_max;
634 float g_pickup_armorbig_anyway;
635 float g_pickup_armorlarge;
636 float g_pickup_armorlarge_max;
637 float g_pickup_armorlarge_anyway;
638 float g_pickup_healthsmall;
639 float g_pickup_healthsmall_max;
640 float g_pickup_healthsmall_anyway;
641 float g_pickup_healthmedium;
642 float g_pickup_healthmedium_max;
643 float g_pickup_healthmedium_anyway;
644 float g_pickup_healthlarge;
645 float g_pickup_healthlarge_max;
646 float g_pickup_healthlarge_anyway;
647 float g_pickup_healthmega;
648 float g_pickup_healthmega_max;
649 float g_pickup_healthmega_anyway;
650 float g_pickup_ammo_anyway;
651 float g_pickup_weapons_anyway;
653 WEPSET_DECLARE_A(g_weaponarena_weapons);
654 float g_weaponarena_random;
655 float g_weaponarena_random_with_laser;
656 string g_weaponarena_list;
657 float g_weaponspeedfactor;
658 float g_weaponratefactor;
659 float g_weapondamagefactor;
660 float g_weaponforcefactor;
661 float g_weaponspreadfactor;
663 WEPSET_DECLARE_A(start_weapons);
664 WEPSET_DECLARE_A(start_weapons_default);
665 WEPSET_DECLARE_A(start_weapons_defaultmask);
667 float start_ammo_shells;
668 float start_ammo_nails;
669 float start_ammo_rockets;
670 float start_ammo_cells;
671 float start_ammo_fuel;
673 float start_armorvalue;
674 WEPSET_DECLARE_A(warmup_start_weapons);
675 WEPSET_DECLARE_A(warmup_start_weapons_default);
676 WEPSET_DECLARE_A(warmup_start_weapons_defaultmask);
677 float warmup_start_ammo_shells;
678 float warmup_start_ammo_nails;
679 float warmup_start_ammo_rockets;
680 float warmup_start_ammo_cells;
681 float warmup_start_ammo_fuel;
682 float warmup_start_health;
683 float warmup_start_armorvalue;
686 entity get_weaponinfo(float w);
688 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
690 var float i = weaponinfo.weapon;
696 if (g_lms || g_ca || allguns)
698 if(weaponinfo.spawnflags & WEP_FLAG_NORMAL)
704 d = (i == WEP_SHOTGUN);
706 d = 0; // weapon is set a few lines later
708 d = (i == WEP_LASER || i == WEP_SHOTGUN);
710 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
711 d |= (i == WEP_HOOK);
712 if(weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED) // never default mutator blocked guns
715 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
717 //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n"));
722 // 4: is set by default?
731 void readplayerstartcvars()
737 // initialize starting values for players
738 WEPSET_CLEAR_A(start_weapons);
739 WEPSET_CLEAR_A(start_weapons_default);
740 WEPSET_CLEAR_A(start_weapons_defaultmask);
742 start_ammo_shells = 0;
743 start_ammo_nails = 0;
744 start_ammo_rockets = 0;
745 start_ammo_cells = 0;
746 start_health = cvar("g_balance_health_start");
747 start_armorvalue = cvar("g_balance_armor_start");
750 WEPSET_CLEAR_A(g_weaponarena_weapons);
752 s = cvar_string("g_weaponarena");
753 if (s == "0" || s == "")
759 if (s == "0" || s == "")
765 // forcibly turn off weaponarena
770 g_weaponarena_list = "All Weapons";
771 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
773 e = get_weaponinfo(j);
774 if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
775 WEPSET_OR_AW(g_weaponarena_weapons, j);
778 else if (s == "most")
781 g_weaponarena_list = "Most Weapons";
782 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
784 e = get_weaponinfo(j);
785 if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
786 if (e.spawnflags & WEP_FLAG_NORMAL)
787 WEPSET_OR_AW(g_weaponarena_weapons, j);
790 else if (s == "none")
793 g_weaponarena_list = "No Weapons";
798 t = tokenize_console(s);
799 g_weaponarena_list = "";
800 for (i = 0; i < t; ++i)
803 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
805 e = get_weaponinfo(j);
808 WEPSET_OR_AW(g_weaponarena_weapons, j);
809 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
815 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
818 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
822 g_weaponarena_random = cvar("g_weaponarena_random");
824 g_weaponarena_random = 0;
825 g_weaponarena_random_with_laser = cvar("g_weaponarena_random_with_laser");
829 g_minstagib = 0; // incompatible
830 g_pinata = 0; // incompatible
831 g_weapon_stay = 0; // incompatible
832 WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons);
834 start_items |= IT_UNLIMITED_AMMO;
836 else if (g_minstagib)
838 g_pinata = 0; // incompatible
839 g_weapon_stay = 0; // incompatible
840 g_bloodloss = 0; // incompatible
842 start_armorvalue = 0;
843 WEPSET_COPY_AW(start_weapons, WEP_MINSTANEX);
844 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
845 start_items |= IT_UNLIMITED_SUPERWEAPONS;
847 if (g_minstagib_invis_alpha <= 0)
848 g_minstagib_invis_alpha = -1;
852 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
854 e = get_weaponinfo(i);
855 float w = want_weapon("g_start_weapon_", e, FALSE);
857 WEPSET_OR_AW(start_weapons, i);
859 WEPSET_OR_AW(start_weapons_default, i);
861 WEPSET_OR_AW(start_weapons_defaultmask, i);
865 if(!cvar("g_use_ammunition"))
866 start_items |= IT_UNLIMITED_AMMO;
868 if(cvar("g_nexball"))
869 start_items |= IT_UNLIMITED_SUPERWEAPONS; // FIXME BAD BAD BAD BAD HACK, NEXBALL SHOULDN'T ABUSE PORTO'S WEAPON SLOT
873 start_ammo_cells = cvar("g_minstagib_ammo_start");
874 start_ammo_fuel = cvar("g_start_ammo_fuel");
876 else if(start_items & IT_UNLIMITED_WEAPON_AMMO)
878 start_ammo_rockets = 999;
879 start_ammo_shells = 999;
880 start_ammo_cells = 999;
881 start_ammo_nails = 999;
882 start_ammo_fuel = 999;
888 start_ammo_shells = cvar("g_lms_start_ammo_shells");
889 start_ammo_nails = cvar("g_lms_start_ammo_nails");
890 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
891 start_ammo_cells = cvar("g_lms_start_ammo_cells");
892 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
896 start_ammo_shells = cvar("g_start_ammo_shells");
897 start_ammo_nails = cvar("g_start_ammo_nails");
898 start_ammo_rockets = cvar("g_start_ammo_rockets");
899 start_ammo_cells = cvar("g_start_ammo_cells");
900 start_ammo_fuel = cvar("g_start_ammo_fuel");
906 start_health = cvar("g_lms_start_health");
907 start_armorvalue = cvar("g_lms_start_armor");
912 warmup_start_ammo_shells = start_ammo_shells;
913 warmup_start_ammo_nails = start_ammo_nails;
914 warmup_start_ammo_rockets = start_ammo_rockets;
915 warmup_start_ammo_cells = start_ammo_cells;
916 warmup_start_ammo_fuel = start_ammo_fuel;
917 warmup_start_health = start_health;
918 warmup_start_armorvalue = start_armorvalue;
919 WEPSET_COPY_AA(warmup_start_weapons, start_weapons);
920 WEPSET_COPY_AA(warmup_start_weapons_default, start_weapons_default);
921 WEPSET_COPY_AA(warmup_start_weapons_defaultmask, start_weapons_defaultmask);
923 if (!g_weaponarena && !g_minstagib && !g_ca)
925 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
926 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
927 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
928 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
929 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
930 warmup_start_health = cvar("g_warmup_start_health");
931 warmup_start_armorvalue = cvar("g_warmup_start_armor");
932 WEPSET_CLEAR_A(warmup_start_weapons);
933 WEPSET_CLEAR_A(warmup_start_weapons_default);
934 WEPSET_CLEAR_A(warmup_start_weapons_defaultmask);
935 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
937 e = get_weaponinfo(i);
938 float w = want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns"));
940 WEPSET_OR_AW(warmup_start_weapons, i);
942 WEPSET_OR_AW(warmup_start_weapons_default, i);
944 WEPSET_OR_AW(warmup_start_weapons_defaultmask, i);
950 start_items |= IT_JETPACK;
952 MUTATOR_CALLHOOK(SetStartItems);
954 if ((start_items & IT_JETPACK) || (g_grappling_hook && WEPSET_CONTAINS_AW(start_weapons, WEP_HOOK)))
956 g_grappling_hook = 0; // these two can't coexist, as they use the same button
957 start_items |= IT_FUEL_REGEN;
958 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
959 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
962 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
964 e = get_weaponinfo(i);
965 if(WEPSET_CONTAINS_AW(start_weapons, i) || WEPSET_CONTAINS_AW(warmup_start_weapons, i))
966 weapon_action(i, WR_PRECACHE);
969 start_ammo_shells = max(0, start_ammo_shells);
970 start_ammo_nails = max(0, start_ammo_nails);
971 start_ammo_cells = max(0, start_ammo_cells);
972 start_ammo_rockets = max(0, start_ammo_rockets);
973 start_ammo_fuel = max(0, start_ammo_fuel);
975 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
976 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
977 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
978 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
979 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
983 float g_bugrigs_planar_movement;
984 float g_bugrigs_planar_movement_car_jumping;
985 float g_bugrigs_reverse_spinning;
986 float g_bugrigs_reverse_speeding;
987 float g_bugrigs_reverse_stopping;
988 float g_bugrigs_air_steering;
989 float g_bugrigs_angle_smoothing;
990 float g_bugrigs_friction_floor;
991 float g_bugrigs_friction_brake;
992 float g_bugrigs_friction_air;
993 float g_bugrigs_accel;
994 float g_bugrigs_speed_ref;
995 float g_bugrigs_speed_pow;
996 float g_bugrigs_steer;
998 float g_touchexplode;
999 float g_touchexplode_radius;
1000 float g_touchexplode_damage;
1001 float g_touchexplode_edgedamage;
1002 float g_touchexplode_force;
1007 string GetGametype(); // g_world.qc
1008 void readlevelcvars(void)
1010 g_minstagib = cvar("g_minstagib");
1012 monster_skill = cvar("g_monsters_skill");
1014 // load ALL the mutators
1015 if(cvar("g_dodging"))
1016 MUTATOR_ADD(mutator_dodging);
1017 if(cvar("g_spawn_near_teammate"))
1018 MUTATOR_ADD(mutator_spawn_near_teammate);
1019 if(cvar("g_physical_items"))
1020 MUTATOR_ADD(mutator_physical_items);
1023 if(cvar("g_invincible_projectiles"))
1024 MUTATOR_ADD(mutator_invincibleprojectiles);
1025 if(cvar("g_new_toys"))
1026 MUTATOR_ADD(mutator_new_toys);
1028 MUTATOR_ADD(mutator_nix);
1029 if(cvar("g_rocket_flying"))
1030 MUTATOR_ADD(mutator_rocketflying);
1031 if(cvar("g_vampire"))
1032 MUTATOR_ADD(mutator_vampire);
1033 if(cvar("g_superspectate"))
1034 MUTATOR_ADD(mutator_superspec);
1037 // is this a mutator? is this a mode?
1038 if(cvar("g_sandbox"))
1039 MUTATOR_ADD(sandbox);
1042 MUTATOR_ADD(mutator_zombie_apocalypse);
1044 if(cvar("sv_allow_fullbright"))
1045 serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
1047 g_bugrigs = cvar("g_bugrigs");
1048 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1049 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1050 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1051 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1052 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1053 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1054 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1055 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1056 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1057 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1058 g_bugrigs_accel = cvar("g_bugrigs_accel");
1059 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1060 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1061 g_bugrigs_steer = cvar("g_bugrigs_steer");
1063 g_touchexplode = cvar("g_touchexplode");
1064 g_touchexplode_radius = cvar("g_touchexplode_radius");
1065 g_touchexplode_damage = cvar("g_touchexplode_damage");
1066 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1067 g_touchexplode_force = cvar("g_touchexplode_force");
1069 sv_clones = cvar("sv_clones");
1070 sv_foginterval = cvar("sv_foginterval");
1071 g_cloaked = cvar("g_cloaked");
1073 g_cloaked = 1; // always enable cloak in CTS
1074 g_jump_grunt = cvar("g_jump_grunt");
1075 g_footsteps = cvar("g_footsteps");
1076 g_grappling_hook = cvar("g_grappling_hook");
1077 g_jetpack = cvar("g_jetpack");
1078 g_midair = cvar("g_midair");
1079 g_norecoil = cvar("g_norecoil");
1080 g_bloodloss = cvar("g_bloodloss");
1081 sv_maxidle = cvar("sv_maxidle");
1082 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1083 sv_autotaunt = cvar("sv_autotaunt");
1084 sv_taunt = cvar("sv_taunt");
1086 inWarmupStage = cvar("g_warmup");
1087 g_warmup_limit = cvar("g_warmup_limit");
1088 g_warmup_allguns = cvar("g_warmup_allguns");
1089 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1091 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1092 inWarmupStage = 0; // these modes cannot work together, sorry
1094 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1095 g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
1096 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1097 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1098 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1099 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1100 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1101 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1102 g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
1103 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1104 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1105 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1106 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1107 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1109 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1110 g_weaponratefactor = cvar("g_weaponratefactor");
1111 g_weapondamagefactor = cvar("g_weapondamagefactor");
1112 g_weaponforcefactor = cvar("g_weaponforcefactor");
1113 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1115 g_pickup_shells = cvar("g_pickup_shells");
1116 g_pickup_shells_max = cvar("g_pickup_shells_max");
1117 g_pickup_nails = cvar("g_pickup_nails");
1118 g_pickup_nails_max = cvar("g_pickup_nails_max");
1119 g_pickup_rockets = cvar("g_pickup_rockets");
1120 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1121 g_pickup_cells = cvar("g_pickup_cells");
1122 g_pickup_cells_max = cvar("g_pickup_cells_max");
1123 g_pickup_fuel = cvar("g_pickup_fuel");
1124 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1125 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1126 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1127 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1128 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1129 g_pickup_armormedium = cvar("g_pickup_armormedium");
1130 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1131 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1132 g_pickup_armorbig = cvar("g_pickup_armorbig");
1133 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1134 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1135 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1136 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1137 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1138 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1139 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1140 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1141 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1142 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1143 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1144 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1145 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1146 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1147 g_pickup_healthmega = cvar("g_pickup_healthmega");
1148 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1149 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1151 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1152 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1154 g_pinata = cvar("g_pinata");
1156 g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
1158 g_weapon_stay = cvar("g_weapon_stay");
1160 if not(inWarmupStage && !g_ca)
1161 game_starttime = cvar("g_start_delay");
1163 readplayerstartcvars();
1169 string precache_sound (string s) = #19;
1170 float precache_sound_index (string s) = #19;
1172 #define SND_VOLUME 1
1173 #define SND_ATTENUATION 2
1174 #define SND_LARGEENTITY 8
1175 #define SND_LARGESOUND 16
1177 float sound_allowed(float dest, entity e)
1179 // sounds from world may always pass
1182 if (e.classname == "body")
1184 else if (e.realowner && e.realowner != e)
1186 else if (e.owner && e.owner != e)
1191 // sounds to self may always pass
1192 if (dest == MSG_ONE)
1193 if (e == msg_entity)
1195 // sounds by players can be removed
1196 if (autocvar_bot_sound_monopoly)
1197 if (clienttype(e) == CLIENTTYPE_REAL)
1199 // anything else may pass
1203 #ifdef COMPAT_XON010_CHANNELS
1204 void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
1205 void sound(entity e, float chan, string samp, float vol, float atten)
1207 if (!sound_allowed(MSG_BROADCAST, e))
1209 builtin_sound(e, chan, samp, vol, atten);
1213 void sound(entity e, float chan, string samp, float vol, float atten)
1215 if (!sound_allowed(MSG_BROADCAST, e))
1217 sound7(e, chan, samp, vol, atten, 0, 0);
1221 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1225 if (!sound_allowed(dest, e))
1228 entno = num_for_edict(e);
1229 idx = precache_sound_index(samp);
1234 atten = floor(atten * 64);
1235 vol = floor(vol * 255);
1238 sflags |= SND_VOLUME;
1240 sflags |= SND_ATTENUATION;
1241 if (entno >= 8192 || chan < 0 || chan > 7)
1242 sflags |= SND_LARGEENTITY;
1244 sflags |= SND_LARGESOUND;
1246 WriteByte(dest, SVC_SOUND);
1247 WriteByte(dest, sflags);
1248 if (sflags & SND_VOLUME)
1249 WriteByte(dest, vol);
1250 if (sflags & SND_ATTENUATION)
1251 WriteByte(dest, atten);
1252 if (sflags & SND_LARGEENTITY)
1254 WriteShort(dest, entno);
1255 WriteByte(dest, chan);
1259 WriteShort(dest, entno * 8 + chan);
1261 if (sflags & SND_LARGESOUND)
1262 WriteShort(dest, idx);
1264 WriteByte(dest, idx);
1266 WriteCoord(dest, o_x);
1267 WriteCoord(dest, o_y);
1268 WriteCoord(dest, o_z);
1270 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1274 if (!sound_allowed(dest, e))
1277 o = e.origin + 0.5 * (e.mins + e.maxs);
1278 soundtoat(dest, e, o, chan, samp, vol, atten);
1280 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1282 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, atten);
1284 void stopsoundto(float dest, entity e, float chan)
1288 if (!sound_allowed(dest, e))
1291 entno = num_for_edict(e);
1293 if (entno >= 8192 || chan < 0 || chan > 7)
1296 idx = precache_sound_index("misc/null.wav");
1297 sflags = SND_LARGEENTITY;
1299 sflags |= SND_LARGESOUND;
1300 WriteByte(dest, SVC_SOUND);
1301 WriteByte(dest, sflags);
1302 WriteShort(dest, entno);
1303 WriteByte(dest, chan);
1304 if (sflags & SND_LARGESOUND)
1305 WriteShort(dest, idx);
1307 WriteByte(dest, idx);
1308 WriteCoord(dest, e.origin_x);
1309 WriteCoord(dest, e.origin_y);
1310 WriteCoord(dest, e.origin_z);
1314 WriteByte(dest, SVC_STOPSOUND);
1315 WriteShort(dest, entno * 8 + chan);
1318 void stopsound(entity e, float chan)
1320 if (!sound_allowed(MSG_BROADCAST, e))
1323 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1324 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1327 void play2(entity e, string filename)
1329 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1331 soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTN_NONE);
1334 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1336 float spamsound(entity e, float chan, string samp, float vol, float atten)
1338 if (!sound_allowed(MSG_BROADCAST, e))
1341 if (time > e.spamtime)
1344 sound(e, chan, samp, vol, atten);
1350 void play2team(float t, string filename)
1354 if (autocvar_bot_sound_monopoly)
1357 FOR_EACH_REALPLAYER(head)
1360 play2(head, filename);
1364 void play2all(string samp)
1366 if (autocvar_bot_sound_monopoly)
1369 sound(world, CH_INFO, samp, VOL_BASE, ATTN_NONE);
1372 void PrecachePlayerSounds(string f);
1373 void precache_playermodel(string m)
1375 float globhandle, i, n;
1378 if(substring(m, -9,5) == "_lod1")
1380 if(substring(m, -9,5) == "_lod2")
1383 f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
1386 f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
1390 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1393 n = search_getsize(globhandle);
1394 for (i = 0; i < n; ++i)
1396 //print(search_getfilename(globhandle, i), "\n");
1397 f = search_getfilename(globhandle, i);
1398 PrecachePlayerSounds(f);
1400 search_end(globhandle);
1402 void precache_all_playermodels(string pattern)
1404 float globhandle, i, n;
1407 globhandle = search_begin(pattern, TRUE, FALSE);
1410 n = search_getsize(globhandle);
1411 for (i = 0; i < n; ++i)
1413 //print(search_getfilename(globhandle, i), "\n");
1414 f = search_getfilename(globhandle, i);
1415 precache_playermodel(f);
1417 search_end(globhandle);
1422 // gamemode related things
1423 precache_model ("models/misc/chatbubble.spr");
1426 precache_model ("models/runematch/curse.mdl");
1427 precache_model ("models/runematch/rune.mdl");
1430 #ifdef TTURRETS_ENABLED
1431 if (autocvar_g_turrets)
1435 // Precache all player models if desired
1436 if (autocvar_sv_precacheplayermodels)
1438 PrecachePlayerSounds("sound/player/default.sounds");
1439 precache_all_playermodels("models/player/*.zym");
1440 precache_all_playermodels("models/player/*.dpm");
1441 precache_all_playermodels("models/player/*.md3");
1442 precache_all_playermodels("models/player/*.psk");
1443 precache_all_playermodels("models/player/*.iqm");
1446 if (autocvar_sv_defaultcharacter)
1449 s = autocvar_sv_defaultplayermodel_red;
1451 precache_playermodel(s);
1452 s = autocvar_sv_defaultplayermodel_blue;
1454 precache_playermodel(s);
1455 s = autocvar_sv_defaultplayermodel_yellow;
1457 precache_playermodel(s);
1458 s = autocvar_sv_defaultplayermodel_pink;
1460 precache_playermodel(s);
1461 s = autocvar_sv_defaultplayermodel;
1463 precache_playermodel(s);
1468 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1469 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1472 // gore and miscellaneous sounds
1473 //precache_sound ("misc/h2ohit.wav");
1474 precache_model ("models/hook.md3");
1475 precache_sound ("misc/armorimpact.wav");
1476 precache_sound ("misc/bodyimpact1.wav");
1477 precache_sound ("misc/bodyimpact2.wav");
1478 precache_sound ("misc/gib.wav");
1479 precache_sound ("misc/gib_splat01.wav");
1480 precache_sound ("misc/gib_splat02.wav");
1481 precache_sound ("misc/gib_splat03.wav");
1482 precache_sound ("misc/gib_splat04.wav");
1483 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1484 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1485 precache_sound ("misc/null.wav");
1486 precache_sound ("misc/spawn.wav");
1487 precache_sound ("misc/talk.wav");
1488 precache_sound ("misc/teleport.wav");
1489 precache_sound ("misc/poweroff.wav");
1490 precache_sound ("player/lava.wav");
1491 precache_sound ("player/slime.wav");
1493 precache_model ("models/sprites/0.spr32");
1494 precache_model ("models/sprites/1.spr32");
1495 precache_model ("models/sprites/2.spr32");
1496 precache_model ("models/sprites/3.spr32");
1497 precache_model ("models/sprites/4.spr32");
1498 precache_model ("models/sprites/5.spr32");
1499 precache_model ("models/sprites/6.spr32");
1500 precache_model ("models/sprites/7.spr32");
1501 precache_model ("models/sprites/8.spr32");
1502 precache_model ("models/sprites/9.spr32");
1503 precache_model ("models/sprites/10.spr32");
1505 // common weapon precaches
1506 precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound here
1507 precache_sound ("weapons/weapon_switch.wav");
1508 precache_sound ("weapons/weaponpickup.wav");
1509 precache_sound ("weapons/unavailable.wav");
1510 precache_sound ("weapons/dryfire.wav");
1511 if (g_grappling_hook)
1513 precache_sound ("weapons/hook_fire.wav"); // hook
1514 precache_sound ("weapons/hook_impact.wav"); // hook
1517 if(autocvar_sv_precacheweapons)
1519 //precache weapon models/sounds
1522 while (wep <= WEP_LAST)
1524 weapon_action(wep, WR_PRECACHE);
1529 precache_model("models/elaser.mdl");
1530 precache_model("models/laser.mdl");
1531 precache_model("models/ebomb.mdl");
1534 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1536 if (!self.noise && self.music) // quake 3 uses the music field
1537 self.noise = self.music;
1539 // plays music for the level if there is any
1542 precache_sound (self.noise);
1543 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1548 // WARNING: this kills the trace globals
1549 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1550 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1552 #define INITPRIO_FIRST 0
1553 #define INITPRIO_GAMETYPE 0
1554 #define INITPRIO_GAMETYPE_FALLBACK 1
1555 #define INITPRIO_FINDTARGET 10
1556 #define INITPRIO_DROPTOFLOOR 20
1557 #define INITPRIO_SETLOCATION 90
1558 #define INITPRIO_LINKDOORS 91
1559 #define INITPRIO_LAST 99
1561 .void(void) initialize_entity;
1562 .float initialize_entity_order;
1563 .entity initialize_entity_next;
1564 entity initialize_entity_first;
1566 void make_safe_for_remove(entity e)
1568 if (e.initialize_entity)
1570 entity ent, prev = world;
1571 for (ent = initialize_entity_first; ent; )
1573 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1575 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1576 // skip it in linked list
1579 prev.initialize_entity_next = ent.initialize_entity_next;
1580 ent = prev.initialize_entity_next;
1584 initialize_entity_first = ent.initialize_entity_next;
1585 ent = initialize_entity_first;
1591 ent = ent.initialize_entity_next;
1597 void objerror(string s)
1599 make_safe_for_remove(self);
1600 builtin_objerror(s);
1603 .float remove_except_protected_forbidden;
1604 void remove_except_protected(entity e)
1606 if(e.remove_except_protected_forbidden)
1607 error("not allowed to remove this at this point");
1611 void remove_unsafely(entity e)
1613 if(e.classname == "spike")
1614 error("Removing spikes is forbidden (crylink bug), please report");
1618 void remove_safely(entity e)
1620 make_safe_for_remove(e);
1624 void InitializeEntity(entity e, void(void) func, float order)
1628 if (!e || e.initialize_entity)
1630 // make a proxy initializer entity
1634 e.classname = "initialize_entity";
1638 e.initialize_entity = func;
1639 e.initialize_entity_order = order;
1641 cur = initialize_entity_first;
1645 if (!cur || cur.initialize_entity_order > order)
1647 // insert between prev and cur
1649 prev.initialize_entity_next = e;
1651 initialize_entity_first = e;
1652 e.initialize_entity_next = cur;
1656 cur = cur.initialize_entity_next;
1659 void InitializeEntitiesRun()
1662 startoflist = initialize_entity_first;
1663 initialize_entity_first = world;
1664 remove = remove_except_protected;
1665 for (self = startoflist; self; self = self.initialize_entity_next)
1667 self.remove_except_protected_forbidden = 1;
1669 for (self = startoflist; self; )
1672 var void(void) func;
1673 e = self.initialize_entity_next;
1674 func = self.initialize_entity;
1675 self.initialize_entity_order = 0;
1676 self.initialize_entity = func_null;
1677 self.initialize_entity_next = world;
1678 self.remove_except_protected_forbidden = 0;
1679 if (self.classname == "initialize_entity")
1683 builtin_remove(self);
1686 //dprint("Delayed initialization: ", self.classname, "\n");
1692 backtrace(strcat("Null function in: ", self.classname, "\n"));
1696 remove = remove_unsafely;
1699 .float uncustomizeentityforclient_set;
1700 .void(void) uncustomizeentityforclient;
1701 void UncustomizeEntitiesRun()
1705 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1706 self.uncustomizeentityforclient();
1709 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1711 e.customizeentityforclient = customizer;
1712 e.uncustomizeentityforclient = uncustomizer;
1713 e.uncustomizeentityforclient_set = !!uncustomizer;
1717 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1720 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1724 if (e.classname == "")
1725 e.classname = "net_linked";
1727 if (e.model == "" || self.modelindex == 0)
1731 setmodel(e, "null");
1735 e.SendEntity = sendfunc;
1736 e.SendFlags = 0xFFFFFF;
1739 e.effects |= EF_NODEPTHTEST;
1743 e.nextthink = time + dt;
1744 e.think = SUB_Remove;
1748 void adaptor_think2touch()
1757 void adaptor_think2use()
1769 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1771 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
1772 self.projectiledeathtype |= HITTYPE_SPLASH;
1773 adaptor_think2use();
1776 // deferred dropping
1777 void DropToFloor_Handler()
1779 builtin_droptofloor();
1780 self.dropped_origin = self.origin;
1785 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1790 float trace_hits_box_a0, trace_hits_box_a1;
1792 float trace_hits_box_1d(float end, float thmi, float thma)
1796 // just check if x is in range
1804 // do the trace with respect to x
1805 // 0 -> end has to stay in thmi -> thma
1806 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1807 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1808 if (trace_hits_box_a0 > trace_hits_box_a1)
1814 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1819 // now it is a trace from 0 to end
1821 trace_hits_box_a0 = 0;
1822 trace_hits_box_a1 = 1;
1824 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1826 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1828 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1834 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1836 return trace_hits_box(start, end, thmi - ma, thma - mi);
1839 float SUB_NoImpactCheck()
1841 // zero hitcontents = this is not the real impact, but either the
1842 // mirror-impact of something hitting the projectile instead of the
1843 // projectile hitting the something, or a touchareagrid one. Neither of
1844 // these stop the projectile from moving, so...
1845 if(trace_dphitcontents == 0)
1847 //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1848 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)));
1851 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1853 if (other == world && self.size != '0 0 0')
1856 tic = self.velocity * sys_frametime;
1857 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1858 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1859 if (trace_fraction >= 1)
1861 dprint("Odd... did not hit...?\n");
1863 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1865 dprint("Detected and prevented the sky-grapple bug.\n");
1873 #define SUB_OwnerCheck() (other && (other == self.owner))
1875 void RemoveGrapplingHook(entity pl);
1876 void W_Crylink_Dequeue(entity e);
1877 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
1879 if(SUB_OwnerCheck())
1881 if(SUB_NoImpactCheck())
1883 if(self.classname == "grapplinghook")
1884 RemoveGrapplingHook(self.realowner);
1885 else if(self.classname == "spike")
1887 W_Crylink_Dequeue(self);
1894 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
1895 UpdateCSQCProjectile(self);
1898 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
1900 #define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
1901 #define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP))
1903 void URI_Get_Callback(float id, float status, string data)
1905 if(url_URI_Get_Callback(id, status, data))
1909 else if (id == URI_GET_DISCARD)
1913 else if (id >= URI_GET_CURL && id <= URI_GET_CURL_END)
1916 Curl_URI_Get_Callback(id, status, data);
1918 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1921 OnlineBanList_URI_Get_Callback(id, status, data);
1925 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1929 string uid2name(string myuid) {
1931 s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
1933 // FIXME remove this later after 0.6 release
1934 // convert old style broken records to correct style
1937 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
1940 db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
1941 db_put(ServerProgsDB, strcat("uid2name", myuid), "");
1946 s = "^1Unregistered Player";
1950 float race_readTime(string map, float pos)
1958 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
1961 string race_readUID(string map, float pos)
1969 return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
1972 float race_readPos(string map, float t) {
1974 for (i = 1; i <= RANKINGS_CNT; ++i)
1975 if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
1978 return 0; // pos is zero if unranked
1981 void race_writeTime(string map, float t, string myuid)
1990 newpos = race_readPos(map, t);
1992 float i, prevpos = 0;
1993 for(i = 1; i <= RANKINGS_CNT; ++i)
1995 if(race_readUID(map, i) == myuid)
1998 if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
1999 for (i = prevpos; i > newpos; --i) {
2000 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
2001 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
2003 } else { // player has no ranked record yet
2004 for (i = RANKINGS_CNT; i > newpos; --i) {
2005 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
2006 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
2010 // store new time itself
2011 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
2012 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
2015 string race_readName(string map, float pos)
2023 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
2026 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2029 vector start, org, delta, end, enddown, mstart;
2032 m = e.dphitcontentsmask;
2033 e.dphitcontentsmask = goodcontents | badcontents;
2036 delta = world.maxs - world.mins;
2040 for (i = 0; i < attempts; ++i)
2042 start_x = org_x + random() * delta_x;
2043 start_y = org_y + random() * delta_y;
2044 start_z = org_z + random() * delta_z;
2046 // rule 1: start inside world bounds, and outside
2047 // solid, and don't start from somewhere where you can
2048 // fall down to evil
2049 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2050 if (trace_fraction >= 1)
2052 if (trace_startsolid)
2054 if (trace_dphitcontents & badcontents)
2056 if (trace_dphitq3surfaceflags & badsurfaceflags)
2059 // rule 2: if we are too high, lower the point
2060 if (trace_fraction * delta_z > maxaboveground)
2061 start = trace_endpos + '0 0 1' * maxaboveground;
2062 enddown = trace_endpos;
2064 // rule 3: make sure we aren't outside the map. This only works
2065 // for somewhat well formed maps. A good rule of thumb is that
2066 // the map should have a convex outside hull.
2067 // these can be traceLINES as we already verified the starting box
2068 mstart = start + 0.5 * (e.mins + e.maxs);
2069 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2070 if (trace_fraction >= 1)
2072 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2073 if (trace_fraction >= 1)
2075 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2076 if (trace_fraction >= 1)
2078 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2079 if (trace_fraction >= 1)
2081 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2082 if (trace_fraction >= 1)
2085 // rule 4: we must "see" some spawnpoint
2086 for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
2087 if(checkpvs(mstart, sp))
2091 for(sp = world; (sp = findflags(sp, flags, FL_ITEM)); )
2092 if(checkpvs(mstart, sp))
2098 // find a random vector to "look at"
2099 end_x = org_x + random() * delta_x;
2100 end_y = org_y + random() * delta_y;
2101 end_z = org_z + random() * delta_z;
2102 end = start + normalize(end - start) * vlen(delta);
2104 // rule 4: start TO end must not be too short
2105 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2106 if (trace_startsolid)
2108 if (trace_fraction < minviewdistance / vlen(delta))
2111 // rule 5: don't want to look at sky
2112 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2115 // rule 6: we must not end up in trigger_hurt
2116 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2122 e.dphitcontentsmask = m;
2126 setorigin(e, start);
2127 e.angles = vectoangles(end - start);
2128 dprint("Needed ", ftos(i + 1), " attempts\n");
2135 float zcurveparticles_effectno;
2136 vector zcurveparticles_start;
2137 float zcurveparticles_spd;
2139 void endzcurveparticles()
2141 if(zcurveparticles_effectno)
2144 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2146 zcurveparticles_effectno = 0;
2149 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2151 spd = bound(0, floor(spd / 16), 32767);
2152 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2154 endzcurveparticles();
2155 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2156 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2157 WriteShort(MSG_BROADCAST, effectno);
2158 WriteCoord(MSG_BROADCAST, start_x);
2159 WriteCoord(MSG_BROADCAST, start_y);
2160 WriteCoord(MSG_BROADCAST, start_z);
2161 zcurveparticles_effectno = effectno;
2162 zcurveparticles_start = start;
2165 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2166 WriteCoord(MSG_BROADCAST, end_x);
2167 WriteCoord(MSG_BROADCAST, end_y);
2168 WriteCoord(MSG_BROADCAST, end_z);
2169 WriteCoord(MSG_BROADCAST, end_dz);
2170 zcurveparticles_spd = spd;
2173 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2176 vector vecxy, velxy;
2178 vecxy = end - start;
2183 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2185 endzcurveparticles();
2186 trailparticles(world, effectno, start, end);
2190 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2191 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2194 void write_recordmarker(entity pl, float tstart, float dt)
2196 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2198 // also write a marker into demo files for demotc-race-record-extractor to find
2201 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2202 " ", ftos(tstart), " ", ftos(dt), "\n"));
2205 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2218 if(allowcenter) // 2: allow center handedness
2231 if(allowcenter) // 2: allow center handedness
2247 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2252 if (autocvar_g_shootfromeye)
2256 if (autocvar_g_shootfromclient) { vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn); }
2257 else { vecs_y = 0; vecs_z -= 2; }
2265 else if (autocvar_g_shootfromcenter)
2270 else if ((s = autocvar_g_shootfromfixedorigin) != "")
2280 else if (autocvar_g_shootfromclient)
2282 vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn);
2287 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2289 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2293 void attach_sameorigin(entity e, entity to, string tag)
2295 vector org, t_forward, t_left, t_up, e_forward, e_up;
2298 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2299 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2300 t_forward = v_forward * tagscale;
2301 t_left = v_right * -tagscale;
2302 t_up = v_up * tagscale;
2304 e.origin_x = org * t_forward;
2305 e.origin_y = org * t_left;
2306 e.origin_z = org * t_up;
2308 // current forward and up directions
2309 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2310 e.angles = AnglesTransform_FromVAngles(e.angles);
2312 e.angles = AnglesTransform_FromAngles(e.angles);
2313 fixedmakevectors(e.angles);
2315 // untransform forward, up!
2316 e_forward_x = v_forward * t_forward;
2317 e_forward_y = v_forward * t_left;
2318 e_forward_z = v_forward * t_up;
2319 e_up_x = v_up * t_forward;
2320 e_up_y = v_up * t_left;
2321 e_up_z = v_up * t_up;
2323 e.angles = fixedvectoangles2(e_forward, e_up);
2324 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2325 e.angles = AnglesTransform_ToVAngles(e.angles);
2327 e.angles = AnglesTransform_ToAngles(e.angles);
2329 setattachment(e, to, tag);
2330 setorigin(e, e.origin);
2333 void detach_sameorigin(entity e)
2336 org = gettaginfo(e, 0);
2337 e.angles = fixedvectoangles2(v_forward, v_up);
2338 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2339 e.angles = AnglesTransform_ToVAngles(e.angles);
2341 e.angles = AnglesTransform_ToAngles(e.angles);
2343 setattachment(e, world, "");
2344 setorigin(e, e.origin);
2347 void follow_sameorigin(entity e, entity to)
2349 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2350 e.aiment = to; // make the hole follow bmodel
2351 e.punchangle = to.angles; // the original angles of bmodel
2352 e.view_ofs = e.origin - to.origin; // relative origin
2353 e.v_angle = e.angles - to.angles; // relative angles
2356 void unfollow_sameorigin(entity e)
2358 e.movetype = MOVETYPE_NONE;
2361 entity gettaginfo_relative_ent;
2362 vector gettaginfo_relative(entity e, float tag)
2364 if (!gettaginfo_relative_ent)
2366 gettaginfo_relative_ent = spawn();
2367 gettaginfo_relative_ent.effects = EF_NODRAW;
2369 gettaginfo_relative_ent.model = e.model;
2370 gettaginfo_relative_ent.modelindex = e.modelindex;
2371 gettaginfo_relative_ent.frame = e.frame;
2372 return gettaginfo(gettaginfo_relative_ent, tag);
2377 float modeleffect_SendEntity(entity to, float sf)
2380 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2383 if(self.velocity != '0 0 0')
2385 if(self.angles != '0 0 0')
2387 if(self.avelocity != '0 0 0')
2390 WriteByte(MSG_ENTITY, f);
2391 WriteShort(MSG_ENTITY, self.modelindex);
2392 WriteByte(MSG_ENTITY, self.skin);
2393 WriteByte(MSG_ENTITY, self.frame);
2394 WriteCoord(MSG_ENTITY, self.origin_x);
2395 WriteCoord(MSG_ENTITY, self.origin_y);
2396 WriteCoord(MSG_ENTITY, self.origin_z);
2399 WriteCoord(MSG_ENTITY, self.velocity_x);
2400 WriteCoord(MSG_ENTITY, self.velocity_y);
2401 WriteCoord(MSG_ENTITY, self.velocity_z);
2405 WriteCoord(MSG_ENTITY, self.angles_x);
2406 WriteCoord(MSG_ENTITY, self.angles_y);
2407 WriteCoord(MSG_ENTITY, self.angles_z);
2411 WriteCoord(MSG_ENTITY, self.avelocity_x);
2412 WriteCoord(MSG_ENTITY, self.avelocity_y);
2413 WriteCoord(MSG_ENTITY, self.avelocity_z);
2415 WriteShort(MSG_ENTITY, self.scale * 256.0);
2416 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2417 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2418 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2419 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2424 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)
2429 e.classname = "modeleffect";
2437 e.teleport_time = t1;
2441 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2445 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2448 sz = max(e.scale, e.scale2);
2449 setsize(e, e.mins * sz, e.maxs * sz);
2450 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2453 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2455 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2458 float randombit(float bits)
2460 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2469 for(f = 1; f <= bits; f *= 2)
2478 r = (r - 1) / (n - 1);
2485 float randombits(float bits, float k, float error_return)
2489 while(k > 0 && bits != r)
2491 r += randombit(bits - r);
2500 void randombit_test(float bits, float iter)
2504 print(ftos(randombit(bits)), "\n");
2509 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2511 if(halflifedist > 0)
2512 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2513 else if(halflifedist < 0)
2514 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2523 #define cvar_string_normal builtin_cvar_string
2524 #define cvar_normal builtin_cvar
2526 string cvar_string_normal(string n)
2528 if not(cvar_type(n) & 1)
2529 backtrace(strcat("Attempt to access undefined cvar: ", n));
2530 return builtin_cvar_string(n);
2533 float cvar_normal(string n)
2535 return stof(cvar_string_normal(n));
2538 #define cvar_set_normal builtin_cvar_set
2546 oself.think = SUB_Remove;
2547 oself.nextthink = time;
2553 Execute func() after time + fdelay.
2554 self when func is executed = self when defer is called
2556 void defer(float fdelay, void() func)
2563 e.think = defer_think;
2564 e.nextthink = time + fdelay;
2567 .string aiment_classname;
2568 .float aiment_deadflag;
2569 void SetMovetypeFollow(entity ent, entity e)
2571 // FIXME this may not be warpzone aware
2572 ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
2573 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.
2574 ent.aiment = e; // make the hole follow bmodel
2575 ent.punchangle = e.angles; // the original angles of bmodel
2576 ent.view_ofs = ent.origin - e.origin; // relative origin
2577 ent.v_angle = ent.angles - e.angles; // relative angles
2578 ent.aiment_classname = strzone(e.classname);
2579 ent.aiment_deadflag = e.deadflag;
2581 void UnsetMovetypeFollow(entity ent)
2583 ent.movetype = MOVETYPE_FLY;
2584 PROJECTILE_MAKETRIGGER(ent);
2587 float LostMovetypeFollow(entity ent)
2590 if(ent.movetype != MOVETYPE_FOLLOW)
2596 if(ent.aiment.classname != ent.aiment_classname)
2598 if(ent.aiment.deadflag != ent.aiment_deadflag)
2604 float isPushable(entity e)
2613 case "droppedweapon":
2614 case "keepawayball":
2615 case "nexball_basketball":
2616 case "nexball_football":
2618 case "bullet": // antilagged bullets can't hit this either
2621 if (e.projectiledeathtype)