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 && IS_PLAYER(p))
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_pinata = 0; // incompatible
828 g_weapon_stay = 0; // incompatible
829 WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons);
830 start_items |= IT_UNLIMITED_AMMO;
834 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
836 e = get_weaponinfo(i);
837 float w = want_weapon("g_start_weapon_", e, FALSE);
839 WEPSET_OR_AW(start_weapons, i);
841 WEPSET_OR_AW(start_weapons_default, i);
843 WEPSET_OR_AW(start_weapons_defaultmask, i);
847 if(!cvar("g_use_ammunition"))
848 start_items |= IT_UNLIMITED_AMMO;
850 if(cvar("g_nexball"))
851 start_items |= IT_UNLIMITED_SUPERWEAPONS; // FIXME BAD BAD BAD BAD HACK, NEXBALL SHOULDN'T ABUSE PORTO'S WEAPON SLOT
853 if(start_items & IT_UNLIMITED_WEAPON_AMMO)
855 start_ammo_rockets = 999;
856 start_ammo_shells = 999;
857 start_ammo_cells = 999;
858 start_ammo_nails = 999;
859 start_ammo_fuel = 999;
863 start_ammo_shells = cvar("g_start_ammo_shells");
864 start_ammo_nails = cvar("g_start_ammo_nails");
865 start_ammo_rockets = cvar("g_start_ammo_rockets");
866 start_ammo_cells = cvar("g_start_ammo_cells");
867 start_ammo_fuel = cvar("g_start_ammo_fuel");
872 warmup_start_ammo_shells = start_ammo_shells;
873 warmup_start_ammo_nails = start_ammo_nails;
874 warmup_start_ammo_rockets = start_ammo_rockets;
875 warmup_start_ammo_cells = start_ammo_cells;
876 warmup_start_ammo_fuel = start_ammo_fuel;
877 warmup_start_health = start_health;
878 warmup_start_armorvalue = start_armorvalue;
879 WEPSET_COPY_AA(warmup_start_weapons, start_weapons);
880 WEPSET_COPY_AA(warmup_start_weapons_default, start_weapons_default);
881 WEPSET_COPY_AA(warmup_start_weapons_defaultmask, start_weapons_defaultmask);
883 if (!g_weaponarena && !g_ca)
885 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
886 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
887 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
888 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
889 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
890 warmup_start_health = cvar("g_warmup_start_health");
891 warmup_start_armorvalue = cvar("g_warmup_start_armor");
892 WEPSET_CLEAR_A(warmup_start_weapons);
893 WEPSET_CLEAR_A(warmup_start_weapons_default);
894 WEPSET_CLEAR_A(warmup_start_weapons_defaultmask);
895 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
897 e = get_weaponinfo(i);
898 float w = want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns"));
900 WEPSET_OR_AW(warmup_start_weapons, i);
902 WEPSET_OR_AW(warmup_start_weapons_default, i);
904 WEPSET_OR_AW(warmup_start_weapons_defaultmask, i);
910 start_items |= IT_JETPACK;
912 MUTATOR_CALLHOOK(SetStartItems);
914 if ((start_items & IT_JETPACK) || (g_grappling_hook && WEPSET_CONTAINS_AW(start_weapons, WEP_HOOK)))
916 g_grappling_hook = 0; // these two can't coexist, as they use the same button
917 start_items |= IT_FUEL_REGEN;
918 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
919 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
922 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
924 e = get_weaponinfo(i);
925 if(WEPSET_CONTAINS_AW(start_weapons, i) || WEPSET_CONTAINS_AW(warmup_start_weapons, i))
926 weapon_action(i, WR_PRECACHE);
929 start_ammo_shells = max(0, start_ammo_shells);
930 start_ammo_nails = max(0, start_ammo_nails);
931 start_ammo_cells = max(0, start_ammo_cells);
932 start_ammo_rockets = max(0, start_ammo_rockets);
933 start_ammo_fuel = max(0, start_ammo_fuel);
935 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
936 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
937 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
938 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
939 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
943 float g_bugrigs_planar_movement;
944 float g_bugrigs_planar_movement_car_jumping;
945 float g_bugrigs_reverse_spinning;
946 float g_bugrigs_reverse_speeding;
947 float g_bugrigs_reverse_stopping;
948 float g_bugrigs_air_steering;
949 float g_bugrigs_angle_smoothing;
950 float g_bugrigs_friction_floor;
951 float g_bugrigs_friction_brake;
952 float g_bugrigs_friction_air;
953 float g_bugrigs_accel;
954 float g_bugrigs_speed_ref;
955 float g_bugrigs_speed_pow;
956 float g_bugrigs_steer;
961 string GetGametype(); // g_world.qc
962 void readlevelcvars(void)
965 #define CHECK_MUTATOR_ADD(mut_cvar,mut_name,dependence) \
966 { if(cvar(mut_cvar) && dependence) { MUTATOR_ADD(mut_name); } }
968 CHECK_MUTATOR_ADD("g_dodging", mutator_dodging, 1);
969 CHECK_MUTATOR_ADD("g_spawn_near_teammate", mutator_spawn_near_teammate, 1);
970 CHECK_MUTATOR_ADD("g_physical_items", mutator_physical_items, 1);
971 CHECK_MUTATOR_ADD("g_touchexplode", mutator_touchexplode, 1);
972 CHECK_MUTATOR_ADD("g_minstagib", mutator_minstagib, 1);
973 CHECK_MUTATOR_ADD("g_invincible_projectiles", mutator_invincibleprojectiles, !cvar("g_minstagib"));
974 CHECK_MUTATOR_ADD("g_new_toys", mutator_new_toys, !cvar("g_minstagib"));
975 CHECK_MUTATOR_ADD("g_nix", mutator_nix, !cvar("g_minstagib"));
976 CHECK_MUTATOR_ADD("g_rocket_flying", mutator_rocketflying, !cvar("g_minstagib"));
977 CHECK_MUTATOR_ADD("g_vampire", mutator_vampire, !cvar("g_minstagib"));
978 CHECK_MUTATOR_ADD("g_superspectate", mutator_superspec, 1);
979 CHECK_MUTATOR_ADD("g_sandbox", sandbox, 1);
981 #undef CHECK_MUTATOR_ADD
983 if(cvar("sv_allow_fullbright"))
984 serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
986 g_bugrigs = cvar("g_bugrigs");
987 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
988 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
989 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
990 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
991 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
992 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
993 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
994 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
995 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
996 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
997 g_bugrigs_accel = cvar("g_bugrigs_accel");
998 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
999 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1000 g_bugrigs_steer = cvar("g_bugrigs_steer");
1002 g_minstagib = cvar("g_minstagib");
1004 sv_clones = cvar("sv_clones");
1005 sv_foginterval = cvar("sv_foginterval");
1006 g_cloaked = cvar("g_cloaked");
1008 g_cloaked = 1; // always enable cloak in CTS
1009 g_jump_grunt = cvar("g_jump_grunt");
1010 g_footsteps = cvar("g_footsteps");
1011 g_grappling_hook = cvar("g_grappling_hook");
1012 g_jetpack = cvar("g_jetpack");
1013 g_midair = cvar("g_midair");
1014 g_norecoil = cvar("g_norecoil");
1015 g_bloodloss = cvar("g_bloodloss");
1016 sv_maxidle = cvar("sv_maxidle");
1017 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1018 sv_autotaunt = cvar("sv_autotaunt");
1019 sv_taunt = cvar("sv_taunt");
1021 inWarmupStage = cvar("g_warmup");
1022 g_warmup_limit = cvar("g_warmup_limit");
1023 g_warmup_allguns = cvar("g_warmup_allguns");
1024 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1026 if ((g_race && g_race_qualifying == 2) || g_arena || g_minstagib || g_assault || cvar("g_campaign"))
1027 inWarmupStage = 0; // these modes cannot work together, sorry
1029 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1030 g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
1031 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1032 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1033 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1034 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1035 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1036 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1037 g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
1038 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1039 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1040 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1041 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1042 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1044 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1045 g_weaponratefactor = cvar("g_weaponratefactor");
1046 g_weapondamagefactor = cvar("g_weapondamagefactor");
1047 g_weaponforcefactor = cvar("g_weaponforcefactor");
1048 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1050 g_pickup_shells = cvar("g_pickup_shells");
1051 g_pickup_shells_max = cvar("g_pickup_shells_max");
1052 g_pickup_nails = cvar("g_pickup_nails");
1053 g_pickup_nails_max = cvar("g_pickup_nails_max");
1054 g_pickup_rockets = cvar("g_pickup_rockets");
1055 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1056 g_pickup_cells = cvar("g_pickup_cells");
1057 g_pickup_cells_max = cvar("g_pickup_cells_max");
1058 g_pickup_fuel = cvar("g_pickup_fuel");
1059 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1060 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1061 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1062 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1063 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1064 g_pickup_armormedium = cvar("g_pickup_armormedium");
1065 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1066 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1067 g_pickup_armorbig = cvar("g_pickup_armorbig");
1068 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1069 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1070 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1071 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1072 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1073 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1074 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1075 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1076 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1077 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1078 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1079 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1080 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1081 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1082 g_pickup_healthmega = cvar("g_pickup_healthmega");
1083 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1084 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1086 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1087 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1089 g_pinata = cvar("g_pinata");
1091 g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
1093 g_weapon_stay = cvar("g_weapon_stay");
1095 if not(inWarmupStage)
1096 game_starttime = time + cvar("g_start_delay");
1098 readplayerstartcvars();
1104 string precache_sound (string s) = #19;
1105 float precache_sound_index (string s) = #19;
1107 #define SND_VOLUME 1
1108 #define SND_ATTENUATION 2
1109 #define SND_LARGEENTITY 8
1110 #define SND_LARGESOUND 16
1112 float sound_allowed(float dest, entity e)
1114 // sounds from world may always pass
1117 if (e.classname == "body")
1119 else if (e.realowner && e.realowner != e)
1121 else if (e.owner && e.owner != e)
1126 // sounds to self may always pass
1127 if (dest == MSG_ONE)
1128 if (e == msg_entity)
1130 // sounds by players can be removed
1131 if (autocvar_bot_sound_monopoly)
1132 if (IS_REAL_CLIENT(e))
1134 // anything else may pass
1138 #ifdef COMPAT_XON010_CHANNELS
1139 void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
1140 void sound(entity e, float chan, string samp, float vol, float atten)
1142 if (!sound_allowed(MSG_BROADCAST, e))
1144 builtin_sound(e, chan, samp, vol, atten);
1148 void sound(entity e, float chan, string samp, float vol, float atten)
1150 if (!sound_allowed(MSG_BROADCAST, e))
1152 sound7(e, chan, samp, vol, atten, 0, 0);
1156 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1160 if (!sound_allowed(dest, e))
1163 entno = num_for_edict(e);
1164 idx = precache_sound_index(samp);
1169 atten = floor(atten * 64);
1170 vol = floor(vol * 255);
1173 sflags |= SND_VOLUME;
1175 sflags |= SND_ATTENUATION;
1176 if (entno >= 8192 || chan < 0 || chan > 7)
1177 sflags |= SND_LARGEENTITY;
1179 sflags |= SND_LARGESOUND;
1181 WriteByte(dest, SVC_SOUND);
1182 WriteByte(dest, sflags);
1183 if (sflags & SND_VOLUME)
1184 WriteByte(dest, vol);
1185 if (sflags & SND_ATTENUATION)
1186 WriteByte(dest, atten);
1187 if (sflags & SND_LARGEENTITY)
1189 WriteShort(dest, entno);
1190 WriteByte(dest, chan);
1194 WriteShort(dest, entno * 8 + chan);
1196 if (sflags & SND_LARGESOUND)
1197 WriteShort(dest, idx);
1199 WriteByte(dest, idx);
1201 WriteCoord(dest, o_x);
1202 WriteCoord(dest, o_y);
1203 WriteCoord(dest, o_z);
1205 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1209 if (!sound_allowed(dest, e))
1212 o = e.origin + 0.5 * (e.mins + e.maxs);
1213 soundtoat(dest, e, o, chan, samp, vol, atten);
1215 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1217 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, atten);
1219 void stopsoundto(float dest, entity e, float chan)
1223 if (!sound_allowed(dest, e))
1226 entno = num_for_edict(e);
1228 if (entno >= 8192 || chan < 0 || chan > 7)
1231 idx = precache_sound_index("misc/null.wav");
1232 sflags = SND_LARGEENTITY;
1234 sflags |= SND_LARGESOUND;
1235 WriteByte(dest, SVC_SOUND);
1236 WriteByte(dest, sflags);
1237 WriteShort(dest, entno);
1238 WriteByte(dest, chan);
1239 if (sflags & SND_LARGESOUND)
1240 WriteShort(dest, idx);
1242 WriteByte(dest, idx);
1243 WriteCoord(dest, e.origin_x);
1244 WriteCoord(dest, e.origin_y);
1245 WriteCoord(dest, e.origin_z);
1249 WriteByte(dest, SVC_STOPSOUND);
1250 WriteShort(dest, entno * 8 + chan);
1253 void stopsound(entity e, float chan)
1255 if (!sound_allowed(MSG_BROADCAST, e))
1258 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1259 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1262 void play2(entity e, string filename)
1264 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1266 soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTN_NONE);
1269 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1271 float spamsound(entity e, float chan, string samp, float vol, float atten)
1273 if (!sound_allowed(MSG_BROADCAST, e))
1276 if (time > e.spamtime)
1279 sound(e, chan, samp, vol, atten);
1285 void play2team(float t, string filename)
1289 if (autocvar_bot_sound_monopoly)
1292 FOR_EACH_REALPLAYER(head)
1295 play2(head, filename);
1299 void play2all(string samp)
1301 if (autocvar_bot_sound_monopoly)
1304 sound(world, CH_INFO, samp, VOL_BASE, ATTN_NONE);
1307 void PrecachePlayerSounds(string f);
1308 void precache_playermodel(string m)
1310 float globhandle, i, n;
1313 if(substring(m, -9,5) == "_lod1")
1315 if(substring(m, -9,5) == "_lod2")
1318 f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
1321 f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
1325 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1328 n = search_getsize(globhandle);
1329 for (i = 0; i < n; ++i)
1331 //print(search_getfilename(globhandle, i), "\n");
1332 f = search_getfilename(globhandle, i);
1333 PrecachePlayerSounds(f);
1335 search_end(globhandle);
1337 void precache_all_playermodels(string pattern)
1339 float globhandle, i, n;
1342 globhandle = search_begin(pattern, TRUE, FALSE);
1345 n = search_getsize(globhandle);
1346 for (i = 0; i < n; ++i)
1348 //print(search_getfilename(globhandle, i), "\n");
1349 f = search_getfilename(globhandle, i);
1350 precache_playermodel(f);
1352 search_end(globhandle);
1357 // gamemode related things
1358 precache_model ("models/misc/chatbubble.spr");
1360 #ifdef TTURRETS_ENABLED
1361 if (autocvar_g_turrets)
1365 // Precache all player models if desired
1366 if (autocvar_sv_precacheplayermodels)
1368 PrecachePlayerSounds("sound/player/default.sounds");
1369 precache_all_playermodels("models/player/*.zym");
1370 precache_all_playermodels("models/player/*.dpm");
1371 precache_all_playermodels("models/player/*.md3");
1372 precache_all_playermodels("models/player/*.psk");
1373 precache_all_playermodels("models/player/*.iqm");
1376 if (autocvar_sv_defaultcharacter)
1379 s = autocvar_sv_defaultplayermodel_red;
1381 precache_playermodel(s);
1382 s = autocvar_sv_defaultplayermodel_blue;
1384 precache_playermodel(s);
1385 s = autocvar_sv_defaultplayermodel_yellow;
1387 precache_playermodel(s);
1388 s = autocvar_sv_defaultplayermodel_pink;
1390 precache_playermodel(s);
1391 s = autocvar_sv_defaultplayermodel;
1393 precache_playermodel(s);
1398 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1399 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1402 // gore and miscellaneous sounds
1403 //precache_sound ("misc/h2ohit.wav");
1404 precache_model ("models/hook.md3");
1405 precache_sound ("misc/armorimpact.wav");
1406 precache_sound ("misc/bodyimpact1.wav");
1407 precache_sound ("misc/bodyimpact2.wav");
1408 precache_sound ("misc/gib.wav");
1409 precache_sound ("misc/gib_splat01.wav");
1410 precache_sound ("misc/gib_splat02.wav");
1411 precache_sound ("misc/gib_splat03.wav");
1412 precache_sound ("misc/gib_splat04.wav");
1413 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1414 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1415 precache_sound ("misc/null.wav");
1416 precache_sound ("misc/spawn.wav");
1417 precache_sound ("misc/talk.wav");
1418 precache_sound ("misc/teleport.wav");
1419 precache_sound ("misc/poweroff.wav");
1420 precache_sound ("player/lava.wav");
1421 precache_sound ("player/slime.wav");
1423 precache_model ("models/sprites/0.spr32");
1424 precache_model ("models/sprites/1.spr32");
1425 precache_model ("models/sprites/2.spr32");
1426 precache_model ("models/sprites/3.spr32");
1427 precache_model ("models/sprites/4.spr32");
1428 precache_model ("models/sprites/5.spr32");
1429 precache_model ("models/sprites/6.spr32");
1430 precache_model ("models/sprites/7.spr32");
1431 precache_model ("models/sprites/8.spr32");
1432 precache_model ("models/sprites/9.spr32");
1433 precache_model ("models/sprites/10.spr32");
1435 // common weapon precaches
1436 precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound here
1437 precache_sound ("weapons/weapon_switch.wav");
1438 precache_sound ("weapons/weaponpickup.wav");
1439 precache_sound ("weapons/unavailable.wav");
1440 precache_sound ("weapons/dryfire.wav");
1441 if (g_grappling_hook)
1443 precache_sound ("weapons/hook_fire.wav"); // hook
1444 precache_sound ("weapons/hook_impact.wav"); // hook
1447 if(autocvar_sv_precacheweapons)
1449 //precache weapon models/sounds
1452 while (wep <= WEP_LAST)
1454 weapon_action(wep, WR_PRECACHE);
1459 precache_model("models/elaser.mdl");
1460 precache_model("models/laser.mdl");
1461 precache_model("models/ebomb.mdl");
1464 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1466 if (!self.noise && self.music) // quake 3 uses the music field
1467 self.noise = self.music;
1469 // plays music for the level if there is any
1472 precache_sound (self.noise);
1473 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1478 // WARNING: this kills the trace globals
1479 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1480 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1482 #define INITPRIO_FIRST 0
1483 #define INITPRIO_GAMETYPE 0
1484 #define INITPRIO_GAMETYPE_FALLBACK 1
1485 #define INITPRIO_FINDTARGET 10
1486 #define INITPRIO_DROPTOFLOOR 20
1487 #define INITPRIO_SETLOCATION 90
1488 #define INITPRIO_LINKDOORS 91
1489 #define INITPRIO_LAST 99
1491 .void(void) initialize_entity;
1492 .float initialize_entity_order;
1493 .entity initialize_entity_next;
1494 entity initialize_entity_first;
1496 void make_safe_for_remove(entity e)
1498 if (e.initialize_entity)
1500 entity ent, prev = world;
1501 for (ent = initialize_entity_first; ent; )
1503 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1505 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1506 // skip it in linked list
1509 prev.initialize_entity_next = ent.initialize_entity_next;
1510 ent = prev.initialize_entity_next;
1514 initialize_entity_first = ent.initialize_entity_next;
1515 ent = initialize_entity_first;
1521 ent = ent.initialize_entity_next;
1527 void objerror(string s)
1529 make_safe_for_remove(self);
1530 builtin_objerror(s);
1533 .float remove_except_protected_forbidden;
1534 void remove_except_protected(entity e)
1536 if(e.remove_except_protected_forbidden)
1537 error("not allowed to remove this at this point");
1541 void remove_unsafely(entity e)
1543 if(e.classname == "spike")
1544 error("Removing spikes is forbidden (crylink bug), please report");
1548 void remove_safely(entity e)
1550 make_safe_for_remove(e);
1554 void InitializeEntity(entity e, void(void) func, float order)
1558 if (!e || e.initialize_entity)
1560 // make a proxy initializer entity
1564 e.classname = "initialize_entity";
1568 e.initialize_entity = func;
1569 e.initialize_entity_order = order;
1571 cur = initialize_entity_first;
1575 if (!cur || cur.initialize_entity_order > order)
1577 // insert between prev and cur
1579 prev.initialize_entity_next = e;
1581 initialize_entity_first = e;
1582 e.initialize_entity_next = cur;
1586 cur = cur.initialize_entity_next;
1589 void InitializeEntitiesRun()
1592 startoflist = initialize_entity_first;
1593 initialize_entity_first = world;
1594 remove = remove_except_protected;
1595 for (self = startoflist; self; self = self.initialize_entity_next)
1597 self.remove_except_protected_forbidden = 1;
1599 for (self = startoflist; self; )
1602 var void(void) func;
1603 e = self.initialize_entity_next;
1604 func = self.initialize_entity;
1605 self.initialize_entity_order = 0;
1606 self.initialize_entity = func_null;
1607 self.initialize_entity_next = world;
1608 self.remove_except_protected_forbidden = 0;
1609 if (self.classname == "initialize_entity")
1613 builtin_remove(self);
1616 //dprint("Delayed initialization: ", self.classname, "\n");
1622 backtrace(strcat("Null function in: ", self.classname, "\n"));
1626 remove = remove_unsafely;
1629 .float uncustomizeentityforclient_set;
1630 .void(void) uncustomizeentityforclient;
1631 void UncustomizeEntitiesRun()
1635 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1636 self.uncustomizeentityforclient();
1639 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1641 e.customizeentityforclient = customizer;
1642 e.uncustomizeentityforclient = uncustomizer;
1643 e.uncustomizeentityforclient_set = !!uncustomizer;
1647 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1650 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1654 if (e.classname == "")
1655 e.classname = "net_linked";
1657 if (e.model == "" || self.modelindex == 0)
1661 setmodel(e, "null");
1665 e.SendEntity = sendfunc;
1666 e.SendFlags = 0xFFFFFF;
1669 e.effects |= EF_NODEPTHTEST;
1673 e.nextthink = time + dt;
1674 e.think = SUB_Remove;
1678 void adaptor_think2touch()
1687 void adaptor_think2use()
1699 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1701 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
1702 self.projectiledeathtype |= HITTYPE_SPLASH;
1703 adaptor_think2use();
1706 // deferred dropping
1707 void DropToFloor_Handler()
1709 builtin_droptofloor();
1710 self.dropped_origin = self.origin;
1715 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1720 float trace_hits_box_a0, trace_hits_box_a1;
1722 float trace_hits_box_1d(float end, float thmi, float thma)
1726 // just check if x is in range
1734 // do the trace with respect to x
1735 // 0 -> end has to stay in thmi -> thma
1736 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1737 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1738 if (trace_hits_box_a0 > trace_hits_box_a1)
1744 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1749 // now it is a trace from 0 to end
1751 trace_hits_box_a0 = 0;
1752 trace_hits_box_a1 = 1;
1754 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1756 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1758 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1764 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1766 return trace_hits_box(start, end, thmi - ma, thma - mi);
1769 float SUB_NoImpactCheck()
1771 // zero hitcontents = this is not the real impact, but either the
1772 // mirror-impact of something hitting the projectile instead of the
1773 // projectile hitting the something, or a touchareagrid one. Neither of
1774 // these stop the projectile from moving, so...
1775 if(trace_dphitcontents == 0)
1777 //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1778 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)));
1781 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1783 if (other == world && self.size != '0 0 0')
1786 tic = self.velocity * sys_frametime;
1787 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1788 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1789 if (trace_fraction >= 1)
1791 dprint("Odd... did not hit...?\n");
1793 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1795 dprint("Detected and prevented the sky-grapple bug.\n");
1803 #define SUB_OwnerCheck() (other && (other == self.owner))
1805 void RemoveGrapplingHook(entity pl);
1806 void W_Crylink_Dequeue(entity e);
1807 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
1809 if(SUB_OwnerCheck())
1811 if(SUB_NoImpactCheck())
1813 if(self.classname == "grapplinghook")
1814 RemoveGrapplingHook(self.realowner);
1815 else if(self.classname == "spike")
1817 W_Crylink_Dequeue(self);
1824 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
1825 UpdateCSQCProjectile(self);
1828 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
1830 #define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
1831 #define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP))
1833 void URI_Get_Callback(float id, float status, string data)
1835 if(url_URI_Get_Callback(id, status, data))
1839 else if (id == URI_GET_DISCARD)
1843 else if (id >= URI_GET_CURL && id <= URI_GET_CURL_END)
1846 Curl_URI_Get_Callback(id, status, data);
1848 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1851 OnlineBanList_URI_Get_Callback(id, status, data);
1855 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1859 string uid2name(string myuid) {
1861 s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
1863 // FIXME remove this later after 0.6 release
1864 // convert old style broken records to correct style
1867 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
1870 db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
1871 db_put(ServerProgsDB, strcat("uid2name", myuid), "");
1876 s = "^1Unregistered Player";
1880 float race_readTime(string map, float pos)
1888 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
1891 string race_readUID(string map, float pos)
1899 return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
1902 float race_readPos(string map, float t) {
1904 for (i = 1; i <= RANKINGS_CNT; ++i)
1905 if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
1908 return 0; // pos is zero if unranked
1911 void race_writeTime(string map, float t, string myuid)
1920 newpos = race_readPos(map, t);
1922 float i, prevpos = 0;
1923 for(i = 1; i <= RANKINGS_CNT; ++i)
1925 if(race_readUID(map, i) == myuid)
1928 if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
1929 for (i = prevpos; i > newpos; --i) {
1930 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
1931 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
1933 } else { // player has no ranked record yet
1934 for (i = RANKINGS_CNT; i > newpos; --i) {
1935 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
1936 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
1940 // store new time itself
1941 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
1942 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
1945 string race_readName(string map, float pos)
1953 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
1956 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
1959 vector start, org, delta, end, enddown, mstart;
1962 m = e.dphitcontentsmask;
1963 e.dphitcontentsmask = goodcontents | badcontents;
1966 delta = world.maxs - world.mins;
1970 for (i = 0; i < attempts; ++i)
1972 start_x = org_x + random() * delta_x;
1973 start_y = org_y + random() * delta_y;
1974 start_z = org_z + random() * delta_z;
1976 // rule 1: start inside world bounds, and outside
1977 // solid, and don't start from somewhere where you can
1978 // fall down to evil
1979 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
1980 if (trace_fraction >= 1)
1982 if (trace_startsolid)
1984 if (trace_dphitcontents & badcontents)
1986 if (trace_dphitq3surfaceflags & badsurfaceflags)
1989 // rule 2: if we are too high, lower the point
1990 if (trace_fraction * delta_z > maxaboveground)
1991 start = trace_endpos + '0 0 1' * maxaboveground;
1992 enddown = trace_endpos;
1994 // rule 3: make sure we aren't outside the map. This only works
1995 // for somewhat well formed maps. A good rule of thumb is that
1996 // the map should have a convex outside hull.
1997 // these can be traceLINES as we already verified the starting box
1998 mstart = start + 0.5 * (e.mins + e.maxs);
1999 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2000 if (trace_fraction >= 1)
2002 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2003 if (trace_fraction >= 1)
2005 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2006 if (trace_fraction >= 1)
2008 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2009 if (trace_fraction >= 1)
2011 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2012 if (trace_fraction >= 1)
2015 // rule 4: we must "see" some spawnpoint
2016 for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
2017 if(checkpvs(mstart, sp))
2021 for(sp = world; (sp = findflags(sp, flags, FL_ITEM)); )
2022 if(checkpvs(mstart, sp))
2028 // find a random vector to "look at"
2029 end_x = org_x + random() * delta_x;
2030 end_y = org_y + random() * delta_y;
2031 end_z = org_z + random() * delta_z;
2032 end = start + normalize(end - start) * vlen(delta);
2034 // rule 4: start TO end must not be too short
2035 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2036 if (trace_startsolid)
2038 if (trace_fraction < minviewdistance / vlen(delta))
2041 // rule 5: don't want to look at sky
2042 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2045 // rule 6: we must not end up in trigger_hurt
2046 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2052 e.dphitcontentsmask = m;
2056 setorigin(e, start);
2057 e.angles = vectoangles(end - start);
2058 dprint("Needed ", ftos(i + 1), " attempts\n");
2065 float zcurveparticles_effectno;
2066 vector zcurveparticles_start;
2067 float zcurveparticles_spd;
2069 void endzcurveparticles()
2071 if(zcurveparticles_effectno)
2074 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2076 zcurveparticles_effectno = 0;
2079 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2081 spd = bound(0, floor(spd / 16), 32767);
2082 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2084 endzcurveparticles();
2085 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2086 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2087 WriteShort(MSG_BROADCAST, effectno);
2088 WriteCoord(MSG_BROADCAST, start_x);
2089 WriteCoord(MSG_BROADCAST, start_y);
2090 WriteCoord(MSG_BROADCAST, start_z);
2091 zcurveparticles_effectno = effectno;
2092 zcurveparticles_start = start;
2095 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2096 WriteCoord(MSG_BROADCAST, end_x);
2097 WriteCoord(MSG_BROADCAST, end_y);
2098 WriteCoord(MSG_BROADCAST, end_z);
2099 WriteCoord(MSG_BROADCAST, end_dz);
2100 zcurveparticles_spd = spd;
2103 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2106 vector vecxy, velxy;
2108 vecxy = end - start;
2113 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2115 endzcurveparticles();
2116 trailparticles(world, effectno, start, end);
2120 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2121 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2124 void write_recordmarker(entity pl, float tstart, float dt)
2126 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2128 // also write a marker into demo files for demotc-race-record-extractor to find
2131 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2132 " ", ftos(tstart), " ", ftos(dt), "\n"));
2135 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2148 if(allowcenter) // 2: allow center handedness
2161 if(allowcenter) // 2: allow center handedness
2177 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2182 if (autocvar_g_shootfromeye)
2186 if (autocvar_g_shootfromclient) { vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn); }
2187 else { vecs_y = 0; vecs_z -= 2; }
2195 else if (autocvar_g_shootfromcenter)
2200 else if ((s = autocvar_g_shootfromfixedorigin) != "")
2210 else if (autocvar_g_shootfromclient)
2212 vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn);
2217 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2219 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2223 void attach_sameorigin(entity e, entity to, string tag)
2225 vector org, t_forward, t_left, t_up, e_forward, e_up;
2228 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2229 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2230 t_forward = v_forward * tagscale;
2231 t_left = v_right * -tagscale;
2232 t_up = v_up * tagscale;
2234 e.origin_x = org * t_forward;
2235 e.origin_y = org * t_left;
2236 e.origin_z = org * t_up;
2238 // current forward and up directions
2239 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2240 e.angles = AnglesTransform_FromVAngles(e.angles);
2242 e.angles = AnglesTransform_FromAngles(e.angles);
2243 fixedmakevectors(e.angles);
2245 // untransform forward, up!
2246 e_forward_x = v_forward * t_forward;
2247 e_forward_y = v_forward * t_left;
2248 e_forward_z = v_forward * t_up;
2249 e_up_x = v_up * t_forward;
2250 e_up_y = v_up * t_left;
2251 e_up_z = v_up * t_up;
2253 e.angles = fixedvectoangles2(e_forward, e_up);
2254 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2255 e.angles = AnglesTransform_ToVAngles(e.angles);
2257 e.angles = AnglesTransform_ToAngles(e.angles);
2259 setattachment(e, to, tag);
2260 setorigin(e, e.origin);
2263 void detach_sameorigin(entity e)
2266 org = gettaginfo(e, 0);
2267 e.angles = fixedvectoangles2(v_forward, v_up);
2268 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2269 e.angles = AnglesTransform_ToVAngles(e.angles);
2271 e.angles = AnglesTransform_ToAngles(e.angles);
2273 setattachment(e, world, "");
2274 setorigin(e, e.origin);
2277 void follow_sameorigin(entity e, entity to)
2279 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2280 e.aiment = to; // make the hole follow bmodel
2281 e.punchangle = to.angles; // the original angles of bmodel
2282 e.view_ofs = e.origin - to.origin; // relative origin
2283 e.v_angle = e.angles - to.angles; // relative angles
2286 void unfollow_sameorigin(entity e)
2288 e.movetype = MOVETYPE_NONE;
2291 entity gettaginfo_relative_ent;
2292 vector gettaginfo_relative(entity e, float tag)
2294 if (!gettaginfo_relative_ent)
2296 gettaginfo_relative_ent = spawn();
2297 gettaginfo_relative_ent.effects = EF_NODRAW;
2299 gettaginfo_relative_ent.model = e.model;
2300 gettaginfo_relative_ent.modelindex = e.modelindex;
2301 gettaginfo_relative_ent.frame = e.frame;
2302 return gettaginfo(gettaginfo_relative_ent, tag);
2307 float modeleffect_SendEntity(entity to, float sf)
2310 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2313 if(self.velocity != '0 0 0')
2315 if(self.angles != '0 0 0')
2317 if(self.avelocity != '0 0 0')
2320 WriteByte(MSG_ENTITY, f);
2321 WriteShort(MSG_ENTITY, self.modelindex);
2322 WriteByte(MSG_ENTITY, self.skin);
2323 WriteByte(MSG_ENTITY, self.frame);
2324 WriteCoord(MSG_ENTITY, self.origin_x);
2325 WriteCoord(MSG_ENTITY, self.origin_y);
2326 WriteCoord(MSG_ENTITY, self.origin_z);
2329 WriteCoord(MSG_ENTITY, self.velocity_x);
2330 WriteCoord(MSG_ENTITY, self.velocity_y);
2331 WriteCoord(MSG_ENTITY, self.velocity_z);
2335 WriteCoord(MSG_ENTITY, self.angles_x);
2336 WriteCoord(MSG_ENTITY, self.angles_y);
2337 WriteCoord(MSG_ENTITY, self.angles_z);
2341 WriteCoord(MSG_ENTITY, self.avelocity_x);
2342 WriteCoord(MSG_ENTITY, self.avelocity_y);
2343 WriteCoord(MSG_ENTITY, self.avelocity_z);
2345 WriteShort(MSG_ENTITY, self.scale * 256.0);
2346 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2347 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2348 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2349 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2354 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)
2359 e.classname = "modeleffect";
2367 e.teleport_time = t1;
2371 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2375 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2378 sz = max(e.scale, e.scale2);
2379 setsize(e, e.mins * sz, e.maxs * sz);
2380 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2383 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2385 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2388 float randombit(float bits)
2390 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2399 for(f = 1; f <= bits; f *= 2)
2408 r = (r - 1) / (n - 1);
2415 float randombits(float bits, float k, float error_return)
2419 while(k > 0 && bits != r)
2421 r += randombit(bits - r);
2430 void randombit_test(float bits, float iter)
2434 print(ftos(randombit(bits)), "\n");
2439 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2441 if(halflifedist > 0)
2442 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2443 else if(halflifedist < 0)
2444 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2453 #define cvar_string_normal builtin_cvar_string
2454 #define cvar_normal builtin_cvar
2456 string cvar_string_normal(string n)
2458 if not(cvar_type(n) & 1)
2459 backtrace(strcat("Attempt to access undefined cvar: ", n));
2460 return builtin_cvar_string(n);
2463 float cvar_normal(string n)
2465 return stof(cvar_string_normal(n));
2468 #define cvar_set_normal builtin_cvar_set
2476 oself.think = SUB_Remove;
2477 oself.nextthink = time;
2483 Execute func() after time + fdelay.
2484 self when func is executed = self when defer is called
2486 void defer(float fdelay, void() func)
2493 e.think = defer_think;
2494 e.nextthink = time + fdelay;
2497 .string aiment_classname;
2498 .float aiment_deadflag;
2499 void SetMovetypeFollow(entity ent, entity e)
2501 // FIXME this may not be warpzone aware
2502 ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
2503 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.
2504 ent.aiment = e; // make the hole follow bmodel
2505 ent.punchangle = e.angles; // the original angles of bmodel
2506 ent.view_ofs = ent.origin - e.origin; // relative origin
2507 ent.v_angle = ent.angles - e.angles; // relative angles
2508 ent.aiment_classname = strzone(e.classname);
2509 ent.aiment_deadflag = e.deadflag;
2511 void UnsetMovetypeFollow(entity ent)
2513 ent.movetype = MOVETYPE_FLY;
2514 PROJECTILE_MAKETRIGGER(ent);
2517 float LostMovetypeFollow(entity ent)
2520 if(ent.movetype != MOVETYPE_FOLLOW)
2526 if(ent.aiment.classname != ent.aiment_classname)
2528 if(ent.aiment.deadflag != ent.aiment_deadflag)
2534 float isPushable(entity e)
2543 case "droppedweapon":
2544 case "keepawayball":
2545 case "nexball_basketball":
2546 case "nexball_football":
2548 case "bullet": // antilagged bullets can't hit this either
2551 if (e.projectiledeathtype)