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)
83 string STR_PLAYER = "player";
84 string STR_SPECTATOR = "spectator";
85 string STR_OBSERVER = "observer";
88 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
89 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
90 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
91 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
93 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
94 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
95 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
96 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
97 #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if(v.classname != STR_PLAYER)
98 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
101 #define CENTER_OR_VIEWOFS(ent) (ent.origin + ((ent.classname == STR_PLAYER) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
103 // copies a string to a tempstring (so one can strunzone it)
104 string strcat1(string s) = #115; // FRIK_FILE
109 void bcenterprint(string s)
111 // TODO replace by MSG_ALL (would show it to spectators too, though)?
113 FOR_EACH_PLAYER(head)
114 if (clienttype(head) == CLIENTTYPE_REAL)
115 centerprint(head, s);
118 void GameLogEcho(string s)
123 if (autocvar_sv_eventlog_files)
128 matches = autocvar_sv_eventlog_files_counter + 1;
129 cvar_set("sv_eventlog_files_counter", ftos(matches));
132 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
133 fn = strcat(autocvar_sv_eventlog_files_nameprefix, fn, autocvar_sv_eventlog_files_namesuffix);
134 logfile = fopen(fn, FILE_APPEND);
135 fputs(logfile, ":logversion:3\n");
139 if (autocvar_sv_eventlog_files_timestamps)
140 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
142 fputs(logfile, strcat(s, "\n"));
145 if (autocvar_sv_eventlog_console)
154 // will be opened later
159 if (logfile_open && logfile >= 0)
166 float spawnpoint_nag;
167 void relocate_spawnpoint()
169 // nudge off the floor
170 setorigin(self, self.origin + '0 0 1');
172 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
173 if (trace_startsolid)
179 if (!move_out_of_solid(self))
180 objerror("could not get out of solid at all!");
181 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
182 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
183 print(" ", ftos(self.origin_y - o_y));
184 print(" ", ftos(self.origin_z - o_z), "'\n");
185 if (autocvar_g_spawnpoints_auto_move_out_of_solid)
188 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
194 self.mins = self.maxs = '0 0 0';
195 objerror("player spawn point in solid, mapper sucks!\n");
200 self.use = spawnpoint_use;
201 self.team_saved = self.team;
205 if (have_team_spawns != 0)
207 have_team_spawns = 1;
208 have_team_spawns_forteam[self.team] = 1;
210 if (autocvar_r_showbboxes)
212 // show where spawnpoints point at too
213 makevectors(self.angles);
216 e.classname = "info_player_foo";
217 setorigin(e, self.origin + v_forward * 24);
218 setsize(e, '-8 -8 -8', '8 8 8');
219 e.solid = SOLID_TRIGGER;
223 #define strstr strstrofs
225 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
226 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
227 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
228 // BE CONSTANT OR strzoneD!
229 float strstr(string haystack, string needle, float offset)
233 len = strlen(needle);
234 endpos = strlen(haystack) - len;
235 while(offset <= endpos)
237 found = substring(haystack, offset, len);
246 float NUM_NEAREST_ENTITIES = 4;
247 entity nearest_entity[NUM_NEAREST_ENTITIES];
248 float nearest_length[NUM_NEAREST_ENTITIES];
249 entity findnearest(vector point, .string field, string value, vector axismod)
260 localhead = find(world, field, value);
263 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
264 dist = localhead.oldorigin;
266 dist = localhead.origin;
268 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
271 for (i = 0; i < num_nearest; ++i)
273 if (len < nearest_length[i])
277 // now i tells us where to insert at
278 // INSERTION SORT! YOU'VE SEEN IT! RUN!
279 if (i < NUM_NEAREST_ENTITIES)
281 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
283 nearest_length[j + 1] = nearest_length[j];
284 nearest_entity[j + 1] = nearest_entity[j];
286 nearest_length[i] = len;
287 nearest_entity[i] = localhead;
288 if (num_nearest < NUM_NEAREST_ENTITIES)
289 num_nearest = num_nearest + 1;
292 localhead = find(localhead, field, value);
295 // now use the first one from our list that we can see
296 for (i = 0; i < num_nearest; ++i)
298 traceline(point, nearest_entity[i].origin, TRUE, world);
299 if (trace_fraction == 1)
303 dprint("Nearest point (");
304 dprint(nearest_entity[0].netname);
305 dprint(") is not visible, using a visible one.\n");
307 return nearest_entity[i];
311 if (num_nearest == 0)
314 dprint("Not seeing any location point, using nearest as fallback.\n");
316 dprint("Candidates were: ");
317 for(j = 0; j < num_nearest; ++j)
321 dprint(nearest_entity[j].netname);
326 return nearest_entity[0];
329 void spawnfunc_target_location()
331 self.classname = "target_location";
332 // location name in netname
333 // eventually support: count, teamgame selectors, line of sight?
336 void spawnfunc_info_location()
338 self.classname = "target_location";
339 self.message = self.netname;
342 string NearestLocation(vector p)
347 loc = findnearest(p, classname, "target_location", '1 1 1');
354 loc = findnearest(p, target, "###item###", '1 1 4');
361 string formatmessage(string msg)
372 WarpZone_crosshair_trace(self);
373 cursor = trace_endpos;
374 cursor_ent = trace_ent;
378 break; // too many replacements
381 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
382 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
395 replacement = substring(msg, p, 2);
396 escape = substring(msg, p + 1, 1);
400 else if (escape == "\\")
402 else if (escape == "n")
404 else if (escape == "a")
405 replacement = ftos(floor(self.armorvalue));
406 else if (escape == "h")
407 replacement = ftos(floor(self.health));
408 else if (escape == "l")
409 replacement = NearestLocation(self.origin);
410 else if (escape == "y")
411 replacement = NearestLocation(cursor);
412 else if (escape == "d")
413 replacement = NearestLocation(self.death_origin);
414 else if (escape == "w") {
418 wep = self.switchweapon;
421 replacement = W_Name(wep);
422 } else if (escape == "W") {
423 if (self.items & IT_SHELLS) replacement = "shells";
424 else if (self.items & IT_NAILS) replacement = "bullets";
425 else if (self.items & IT_ROCKETS) replacement = "rockets";
426 else if (self.items & IT_CELLS) replacement = "cells";
427 else replacement = "batteries"; // ;)
428 } else if (escape == "x") {
429 replacement = cursor_ent.netname;
430 if (!replacement || !cursor_ent)
431 replacement = "nothing";
432 } else if (escape == "s")
433 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
434 else if (escape == "S")
435 replacement = ftos(vlen(self.velocity));
437 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
438 p = p + strlen(replacement);
443 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
444 return (value == 0) ? FALSE : TRUE;
453 >0: receives a cvar from name=argv(f) value=argv(f+1)
455 void GetCvars_handleString(string thisname, float f, .string field, string name)
460 strunzone(self.field);
461 self.field = string_null;
465 if (thisname == name)
468 strunzone(self.field);
469 self.field = strzone(argv(f + 1));
473 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
475 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
477 GetCvars_handleString(thisname, f, field, name);
478 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
479 if (thisname == name)
482 s = func(strcat1(self.field));
485 strunzone(self.field);
486 self.field = strzone(s);
490 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
497 if (thisname == name)
498 self.field = stof(argv(f + 1));
501 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
503 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
510 if (thisname == name)
514 self.field = stof(argv(f + 1));
523 stuffcmd(self, strcat("cl_cmd sendcvar ", name, "\n"));
526 float w_getbestweapon(entity e);
527 string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(string wo)
530 o = W_FixWeaponOrder_ForceComplete(wo);
531 if(self.weaponorder_byimpulse)
533 strunzone(self.weaponorder_byimpulse);
534 self.weaponorder_byimpulse = string_null;
536 self.weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
539 void GetCvars(float f)
541 string s = string_null;
544 s = strcat1(argv(f));
548 MUTATOR_CALLHOOK(GetCvars);
549 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
550 GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
551 GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
552 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
553 GetCvars_handleFloat(s, f, cvar_cl_clippedspectating, "cl_clippedspectating");
554 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
555 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
556 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
557 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
558 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
559 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
560 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
561 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
562 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
563 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
564 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
565 GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode");
566 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
567 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
568 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
569 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
570 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
571 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
573 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
574 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
576 #ifdef ALLOW_FORCEMODELS
577 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
578 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromxonotic, "cl_forceplayermodelsfromxonotic");
580 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
581 GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
582 GetCvars_handleFloat(s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
583 GetCvars_handleFloat(s, f, cvar_cl_movement_track_canjump, "cl_movement_track_canjump");
584 GetCvars_handleFloat(s, f, cvar_cl_newusekeysupported, "cl_newusekeysupported");
586 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
589 if (s == "cl_weaponpriority")
590 self.switchweapon = w_getbestweapon(self);
591 if (s == "cl_allow_uidtracking")
592 PlayerStats_AddPlayer(self);
596 void backtrace(string msg)
599 dev = autocvar_developer;
600 war = autocvar_prvm_backtraceforwarnings;
601 cvar_set("developer", "1");
602 cvar_set("prvm_backtraceforwarnings", "1");
604 print("--- CUT HERE ---\nWARNING: ");
607 remove(world); // isn't there any better way to cause a backtrace?
608 print("\n--- CUT UNTIL HERE ---\n");
609 cvar_set("developer", ftos(dev));
610 cvar_set("prvm_backtraceforwarnings", ftos(war));
613 // decolorizes and team colors the player name when needed
614 string playername(entity p)
617 if (teamplay && !intermission_running && p.classname == "player")
619 t = Team_ColorCode(p.team);
620 return strcat(t, strdecolorize(p.netname));
626 vector randompos(vector m1, vector m2)
630 v_x = m2_x * random() + m1_x;
631 v_y = m2_y * random() + m1_y;
632 v_z = m2_z * random() + m1_z;
636 //#NO AUTOCVARS START
638 float g_pickup_shells;
639 float g_pickup_shells_max;
640 float g_pickup_nails;
641 float g_pickup_nails_max;
642 float g_pickup_rockets;
643 float g_pickup_rockets_max;
644 float g_pickup_cells;
645 float g_pickup_cells_max;
647 float g_pickup_fuel_jetpack;
648 float g_pickup_fuel_max;
649 float g_pickup_armorsmall;
650 float g_pickup_armorsmall_max;
651 float g_pickup_armorsmall_anyway;
652 float g_pickup_armormedium;
653 float g_pickup_armormedium_max;
654 float g_pickup_armormedium_anyway;
655 float g_pickup_armorbig;
656 float g_pickup_armorbig_max;
657 float g_pickup_armorbig_anyway;
658 float g_pickup_armorlarge;
659 float g_pickup_armorlarge_max;
660 float g_pickup_armorlarge_anyway;
661 float g_pickup_healthsmall;
662 float g_pickup_healthsmall_max;
663 float g_pickup_healthsmall_anyway;
664 float g_pickup_healthmedium;
665 float g_pickup_healthmedium_max;
666 float g_pickup_healthmedium_anyway;
667 float g_pickup_healthlarge;
668 float g_pickup_healthlarge_max;
669 float g_pickup_healthlarge_anyway;
670 float g_pickup_healthmega;
671 float g_pickup_healthmega_max;
672 float g_pickup_healthmega_anyway;
673 float g_pickup_ammo_anyway;
674 float g_pickup_weapons_anyway;
676 WEPSET_DECLARE_A(g_weaponarena_weapons);
677 float g_weaponarena_random;
678 float g_weaponarena_random_with_laser;
679 string g_weaponarena_list;
680 float g_weaponspeedfactor;
681 float g_weaponratefactor;
682 float g_weapondamagefactor;
683 float g_weaponforcefactor;
684 float g_weaponspreadfactor;
686 WEPSET_DECLARE_A(start_weapons);
687 WEPSET_DECLARE_A(start_weapons_default);
688 WEPSET_DECLARE_A(start_weapons_defaultmask);
690 float start_ammo_shells;
691 float start_ammo_nails;
692 float start_ammo_rockets;
693 float start_ammo_cells;
694 float start_ammo_fuel;
696 float start_armorvalue;
697 WEPSET_DECLARE_A(warmup_start_weapons);
698 WEPSET_DECLARE_A(warmup_start_weapons_default);
699 WEPSET_DECLARE_A(warmup_start_weapons_defaultmask);
700 float warmup_start_ammo_shells;
701 float warmup_start_ammo_nails;
702 float warmup_start_ammo_rockets;
703 float warmup_start_ammo_cells;
704 float warmup_start_ammo_fuel;
705 float warmup_start_health;
706 float warmup_start_armorvalue;
709 entity get_weaponinfo(float w);
711 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
713 var float i = weaponinfo.weapon;
719 if (g_lms || g_ca || allguns)
721 if(weaponinfo.spawnflags & WEP_FLAG_NORMAL)
727 d = (i == WEP_SHOTGUN);
729 d = 0; // weapon is set a few lines later
731 d = (i == WEP_LASER || i == WEP_SHOTGUN);
733 if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook
734 d |= (i == WEP_HOOK);
735 if(weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED) // never default mutator blocked guns
738 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
740 //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n"));
745 // 4: is set by default?
754 void readplayerstartcvars()
760 // initialize starting values for players
761 WEPSET_CLEAR_A(start_weapons);
762 WEPSET_CLEAR_A(start_weapons_default);
763 WEPSET_CLEAR_A(start_weapons_defaultmask);
765 start_ammo_shells = 0;
766 start_ammo_nails = 0;
767 start_ammo_rockets = 0;
768 start_ammo_cells = 0;
769 start_health = cvar("g_balance_health_start");
770 start_armorvalue = cvar("g_balance_armor_start");
773 WEPSET_CLEAR_A(g_weaponarena_weapons);
775 s = cvar_string("g_weaponarena");
776 if (s == "0" || s == "")
782 if (s == "0" || s == "")
788 // forcibly turn off weaponarena
793 g_weaponarena_list = "All Weapons";
794 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
796 e = get_weaponinfo(j);
797 if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
798 WEPSET_OR_AW(g_weaponarena_weapons, j);
801 else if (s == "most")
804 g_weaponarena_list = "Most Weapons";
805 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
807 e = get_weaponinfo(j);
808 if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
809 if (e.spawnflags & WEP_FLAG_NORMAL)
810 WEPSET_OR_AW(g_weaponarena_weapons, j);
813 else if (s == "none")
816 g_weaponarena_list = "No Weapons";
821 t = tokenize_console(s);
822 g_weaponarena_list = "";
823 for (i = 0; i < t; ++i)
826 for (j = WEP_FIRST; j <= WEP_LAST; ++j)
828 e = get_weaponinfo(j);
831 WEPSET_OR_AW(g_weaponarena_weapons, j);
832 g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & ");
838 print("The weapon mutator list contains an unknown weapon ", s, ". Skipped.\n");
841 g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
845 g_weaponarena_random = cvar("g_weaponarena_random");
847 g_weaponarena_random = 0;
848 g_weaponarena_random_with_laser = cvar("g_weaponarena_random_with_laser");
852 g_minstagib = 0; // incompatible
853 g_pinata = 0; // incompatible
854 g_weapon_stay = 0; // incompatible
855 WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons);
857 start_items |= IT_UNLIMITED_AMMO;
859 else if (g_minstagib)
861 g_pinata = 0; // incompatible
862 g_weapon_stay = 0; // incompatible
863 g_bloodloss = 0; // incompatible
865 start_armorvalue = 0;
866 WEPSET_COPY_AW(start_weapons, WEP_MINSTANEX);
867 g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
868 start_items |= IT_UNLIMITED_SUPERWEAPONS;
870 if (g_minstagib_invis_alpha <= 0)
871 g_minstagib_invis_alpha = -1;
875 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
877 e = get_weaponinfo(i);
878 float w = want_weapon("g_start_weapon_", e, FALSE);
880 WEPSET_OR_AW(start_weapons, i);
882 WEPSET_OR_AW(start_weapons_default, i);
884 WEPSET_OR_AW(start_weapons_defaultmask, i);
888 if(!cvar("g_use_ammunition"))
889 start_items |= IT_UNLIMITED_AMMO;
891 if(cvar("g_nexball"))
892 start_items |= IT_UNLIMITED_SUPERWEAPONS; // FIXME BAD BAD BAD BAD HACK, NEXBALL SHOULDN'T ABUSE PORTO'S WEAPON SLOT
896 start_ammo_cells = cvar("g_minstagib_ammo_start");
897 start_ammo_fuel = cvar("g_start_ammo_fuel");
899 else if(start_items & IT_UNLIMITED_WEAPON_AMMO)
901 start_ammo_rockets = 999;
902 start_ammo_shells = 999;
903 start_ammo_cells = 999;
904 start_ammo_nails = 999;
905 start_ammo_fuel = 999;
911 start_ammo_shells = cvar("g_lms_start_ammo_shells");
912 start_ammo_nails = cvar("g_lms_start_ammo_nails");
913 start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
914 start_ammo_cells = cvar("g_lms_start_ammo_cells");
915 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
919 start_ammo_shells = cvar("g_start_ammo_shells");
920 start_ammo_nails = cvar("g_start_ammo_nails");
921 start_ammo_rockets = cvar("g_start_ammo_rockets");
922 start_ammo_cells = cvar("g_start_ammo_cells");
923 start_ammo_fuel = cvar("g_start_ammo_fuel");
929 start_health = cvar("g_lms_start_health");
930 start_armorvalue = cvar("g_lms_start_armor");
935 warmup_start_ammo_shells = start_ammo_shells;
936 warmup_start_ammo_nails = start_ammo_nails;
937 warmup_start_ammo_rockets = start_ammo_rockets;
938 warmup_start_ammo_cells = start_ammo_cells;
939 warmup_start_ammo_fuel = start_ammo_fuel;
940 warmup_start_health = start_health;
941 warmup_start_armorvalue = start_armorvalue;
942 WEPSET_COPY_AA(warmup_start_weapons, start_weapons);
943 WEPSET_COPY_AA(warmup_start_weapons_default, start_weapons_default);
944 WEPSET_COPY_AA(warmup_start_weapons_defaultmask, start_weapons_defaultmask);
946 if (!g_weaponarena && !g_minstagib && !g_ca)
948 warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
949 warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
950 warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
951 warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
952 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
953 warmup_start_health = cvar("g_warmup_start_health");
954 warmup_start_armorvalue = cvar("g_warmup_start_armor");
955 WEPSET_CLEAR_A(warmup_start_weapons);
956 WEPSET_CLEAR_A(warmup_start_weapons_default);
957 WEPSET_CLEAR_A(warmup_start_weapons_defaultmask);
958 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
960 e = get_weaponinfo(i);
961 float w = want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns"));
963 WEPSET_OR_AW(warmup_start_weapons, i);
965 WEPSET_OR_AW(warmup_start_weapons_default, i);
967 WEPSET_OR_AW(warmup_start_weapons_defaultmask, i);
973 start_items |= IT_JETPACK;
975 MUTATOR_CALLHOOK(SetStartItems);
977 if ((start_items & IT_JETPACK) || (g_grappling_hook && WEPSET_CONTAINS_AW(start_weapons, WEP_HOOK)))
979 g_grappling_hook = 0; // these two can't coexist, as they use the same button
980 start_items |= IT_FUEL_REGEN;
981 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
982 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
985 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
987 e = get_weaponinfo(i);
988 if(WEPSET_CONTAINS_AW(start_weapons, i) || WEPSET_CONTAINS_AW(warmup_start_weapons, i))
989 weapon_action(i, WR_PRECACHE);
992 start_ammo_shells = max(0, start_ammo_shells);
993 start_ammo_nails = max(0, start_ammo_nails);
994 start_ammo_cells = max(0, start_ammo_cells);
995 start_ammo_rockets = max(0, start_ammo_rockets);
996 start_ammo_fuel = max(0, start_ammo_fuel);
998 warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
999 warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
1000 warmup_start_ammo_cells = max(0, warmup_start_ammo_cells);
1001 warmup_start_ammo_rockets = max(0, warmup_start_ammo_rockets);
1002 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
1006 float g_bugrigs_planar_movement;
1007 float g_bugrigs_planar_movement_car_jumping;
1008 float g_bugrigs_reverse_spinning;
1009 float g_bugrigs_reverse_speeding;
1010 float g_bugrigs_reverse_stopping;
1011 float g_bugrigs_air_steering;
1012 float g_bugrigs_angle_smoothing;
1013 float g_bugrigs_friction_floor;
1014 float g_bugrigs_friction_brake;
1015 float g_bugrigs_friction_air;
1016 float g_bugrigs_accel;
1017 float g_bugrigs_speed_ref;
1018 float g_bugrigs_speed_pow;
1019 float g_bugrigs_steer;
1021 float g_touchexplode;
1022 float g_touchexplode_radius;
1023 float g_touchexplode_damage;
1024 float g_touchexplode_edgedamage;
1025 float g_touchexplode_force;
1032 float sv_pitch_fixyaw;
1034 string GetGametype(); // g_world.qc
1035 void readlevelcvars(void)
1037 g_minstagib = cvar("g_minstagib");
1039 // load ALL the mutators
1040 if(cvar("g_dodging"))
1041 MUTATOR_ADD(mutator_dodging);
1042 if(cvar("g_spawn_near_teammate"))
1043 MUTATOR_ADD(mutator_spawn_near_teammate);
1046 if(cvar("g_invincible_projectiles"))
1047 MUTATOR_ADD(mutator_invincibleprojectiles);
1048 if(cvar("g_new_toys"))
1049 MUTATOR_ADD(mutator_new_toys);
1051 MUTATOR_ADD(mutator_nix);
1052 if(cvar("g_rocket_flying"))
1053 MUTATOR_ADD(mutator_rocketflying);
1054 if(cvar("g_vampire"))
1055 MUTATOR_ADD(mutator_vampire);
1056 if(cvar("g_superspectate"))
1057 MUTATOR_ADD(mutator_superspec);
1060 // is this a mutator? is this a mode?
1061 if(cvar("g_sandbox"))
1062 MUTATOR_ADD(sandbox);
1064 if(cvar("sv_allow_fullbright"))
1065 serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
1067 g_bugrigs = cvar("g_bugrigs");
1068 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
1069 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
1070 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
1071 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
1072 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
1073 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
1074 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
1075 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
1076 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
1077 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
1078 g_bugrigs_accel = cvar("g_bugrigs_accel");
1079 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
1080 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
1081 g_bugrigs_steer = cvar("g_bugrigs_steer");
1083 g_touchexplode = cvar("g_touchexplode");
1084 g_touchexplode_radius = cvar("g_touchexplode_radius");
1085 g_touchexplode_damage = cvar("g_touchexplode_damage");
1086 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
1087 g_touchexplode_force = cvar("g_touchexplode_force");
1089 #ifdef ALLOW_FORCEMODELS
1090 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
1093 sv_clones = cvar("sv_clones");
1094 sv_foginterval = cvar("sv_foginterval");
1095 g_cloaked = cvar("g_cloaked");
1097 g_cloaked = 1; // always enable cloak in CTS
1098 g_jump_grunt = cvar("g_jump_grunt");
1099 g_footsteps = cvar("g_footsteps");
1100 g_grappling_hook = cvar("g_grappling_hook");
1101 g_jetpack = cvar("g_jetpack");
1102 g_midair = cvar("g_midair");
1103 g_norecoil = cvar("g_norecoil");
1104 g_bloodloss = cvar("g_bloodloss");
1105 sv_maxidle = cvar("sv_maxidle");
1106 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
1107 sv_autotaunt = cvar("sv_autotaunt");
1108 sv_taunt = cvar("sv_taunt");
1110 inWarmupStage = cvar("g_warmup");
1111 g_warmup_limit = cvar("g_warmup_limit");
1112 g_warmup_allguns = cvar("g_warmup_allguns");
1113 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
1115 if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
1116 inWarmupStage = 0; // these modes cannot work together, sorry
1118 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
1119 g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
1120 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
1121 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
1122 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
1123 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
1124 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
1125 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
1126 g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
1127 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
1128 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
1129 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
1130 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
1131 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
1133 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
1134 g_weaponratefactor = cvar("g_weaponratefactor");
1135 g_weapondamagefactor = cvar("g_weapondamagefactor");
1136 g_weaponforcefactor = cvar("g_weaponforcefactor");
1137 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
1139 g_pickup_shells = cvar("g_pickup_shells");
1140 g_pickup_shells_max = cvar("g_pickup_shells_max");
1141 g_pickup_nails = cvar("g_pickup_nails");
1142 g_pickup_nails_max = cvar("g_pickup_nails_max");
1143 g_pickup_rockets = cvar("g_pickup_rockets");
1144 g_pickup_rockets_max = cvar("g_pickup_rockets_max");
1145 g_pickup_cells = cvar("g_pickup_cells");
1146 g_pickup_cells_max = cvar("g_pickup_cells_max");
1147 g_pickup_fuel = cvar("g_pickup_fuel");
1148 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
1149 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
1150 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
1151 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
1152 g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
1153 g_pickup_armormedium = cvar("g_pickup_armormedium");
1154 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
1155 g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
1156 g_pickup_armorbig = cvar("g_pickup_armorbig");
1157 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
1158 g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
1159 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
1160 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
1161 g_pickup_armorlarge_anyway = cvar("g_pickup_armorlarge_anyway");
1162 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
1163 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
1164 g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
1165 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
1166 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
1167 g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
1168 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
1169 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
1170 g_pickup_healthlarge_anyway = cvar("g_pickup_healthlarge_anyway");
1171 g_pickup_healthmega = cvar("g_pickup_healthmega");
1172 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
1173 g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
1175 g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
1176 g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
1178 g_pinata = cvar("g_pinata");
1180 g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
1182 g_weapon_stay = cvar("g_weapon_stay");
1184 if not(inWarmupStage && !g_ca)
1185 game_starttime = cvar("g_start_delay");
1187 sv_pitch_min = cvar("sv_pitch_min");
1188 sv_pitch_max = cvar("sv_pitch_max");
1189 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
1191 readplayerstartcvars();
1197 string precache_sound (string s) = #19;
1198 float precache_sound_index (string s) = #19;
1200 #define SND_VOLUME 1
1201 #define SND_ATTENUATION 2
1202 #define SND_LARGEENTITY 8
1203 #define SND_LARGESOUND 16
1205 float sound_allowed(float dest, entity e)
1207 // sounds from world may always pass
1210 if (e.classname == "body")
1212 else if (e.realowner && e.realowner != e)
1214 else if (e.owner && e.owner != e)
1219 // sounds to self may always pass
1220 if (dest == MSG_ONE)
1221 if (e == msg_entity)
1223 // sounds by players can be removed
1224 if (autocvar_bot_sound_monopoly)
1225 if (clienttype(e) == CLIENTTYPE_REAL)
1227 // anything else may pass
1231 #ifdef COMPAT_XON010_CHANNELS
1232 void(entity e, float chan, string samp, float vol, float atten) builtin_sound = #8;
1233 void sound(entity e, float chan, string samp, float vol, float atten)
1235 if (!sound_allowed(MSG_BROADCAST, e))
1237 builtin_sound(e, chan, samp, vol, atten);
1241 void sound(entity e, float chan, string samp, float vol, float atten)
1243 if (!sound_allowed(MSG_BROADCAST, e))
1245 sound7(e, chan, samp, vol, atten, 0, 0);
1249 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
1253 if (!sound_allowed(dest, e))
1256 entno = num_for_edict(e);
1257 idx = precache_sound_index(samp);
1262 atten = floor(atten * 64);
1263 vol = floor(vol * 255);
1266 sflags |= SND_VOLUME;
1268 sflags |= SND_ATTENUATION;
1269 if (entno >= 8192 || chan < 0 || chan > 7)
1270 sflags |= SND_LARGEENTITY;
1272 sflags |= SND_LARGESOUND;
1274 WriteByte(dest, SVC_SOUND);
1275 WriteByte(dest, sflags);
1276 if (sflags & SND_VOLUME)
1277 WriteByte(dest, vol);
1278 if (sflags & SND_ATTENUATION)
1279 WriteByte(dest, atten);
1280 if (sflags & SND_LARGEENTITY)
1282 WriteShort(dest, entno);
1283 WriteByte(dest, chan);
1287 WriteShort(dest, entno * 8 + chan);
1289 if (sflags & SND_LARGESOUND)
1290 WriteShort(dest, idx);
1292 WriteByte(dest, idx);
1294 WriteCoord(dest, o_x);
1295 WriteCoord(dest, o_y);
1296 WriteCoord(dest, o_z);
1298 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
1302 if (!sound_allowed(dest, e))
1305 o = e.origin + 0.5 * (e.mins + e.maxs);
1306 soundtoat(dest, e, o, chan, samp, vol, atten);
1308 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
1310 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, atten);
1312 void stopsoundto(float dest, entity e, float chan)
1316 if (!sound_allowed(dest, e))
1319 entno = num_for_edict(e);
1321 if (entno >= 8192 || chan < 0 || chan > 7)
1324 idx = precache_sound_index("misc/null.wav");
1325 sflags = SND_LARGEENTITY;
1327 sflags |= SND_LARGESOUND;
1328 WriteByte(dest, SVC_SOUND);
1329 WriteByte(dest, sflags);
1330 WriteShort(dest, entno);
1331 WriteByte(dest, chan);
1332 if (sflags & SND_LARGESOUND)
1333 WriteShort(dest, idx);
1335 WriteByte(dest, idx);
1336 WriteCoord(dest, e.origin_x);
1337 WriteCoord(dest, e.origin_y);
1338 WriteCoord(dest, e.origin_z);
1342 WriteByte(dest, SVC_STOPSOUND);
1343 WriteShort(dest, entno * 8 + chan);
1346 void stopsound(entity e, float chan)
1348 if (!sound_allowed(MSG_BROADCAST, e))
1351 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
1352 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
1355 void play2(entity e, string filename)
1357 //stuffcmd(e, strcat("play2 ", filename, "\n"));
1359 soundtoat(MSG_ONE, world, '0 0 0', CH_INFO, filename, VOL_BASE, ATTN_NONE);
1362 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
1364 float spamsound(entity e, float chan, string samp, float vol, float atten)
1366 if (!sound_allowed(MSG_BROADCAST, e))
1369 if (time > e.spamtime)
1372 sound(e, chan, samp, vol, atten);
1378 void play2team(float t, string filename)
1382 if (autocvar_bot_sound_monopoly)
1385 FOR_EACH_REALPLAYER(head)
1388 play2(head, filename);
1392 void play2all(string samp)
1394 if (autocvar_bot_sound_monopoly)
1397 sound(world, CH_INFO, samp, VOL_BASE, ATTN_NONE);
1400 void PrecachePlayerSounds(string f);
1401 void precache_playermodel(string m)
1403 float globhandle, i, n;
1406 if(substring(m, -9,5) == "_lod1")
1408 if(substring(m, -9,5) == "_lod2")
1411 f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
1414 f = strcat(substring(m, 0, -5), "_lod2", substring(m, -4, -1));
1418 globhandle = search_begin(strcat(m, "_*.sounds"), TRUE, FALSE);
1421 n = search_getsize(globhandle);
1422 for (i = 0; i < n; ++i)
1424 //print(search_getfilename(globhandle, i), "\n");
1425 f = search_getfilename(globhandle, i);
1426 PrecachePlayerSounds(f);
1428 search_end(globhandle);
1430 void precache_all_playermodels(string pattern)
1432 float globhandle, i, n;
1435 globhandle = search_begin(pattern, TRUE, FALSE);
1438 n = search_getsize(globhandle);
1439 for (i = 0; i < n; ++i)
1441 //print(search_getfilename(globhandle, i), "\n");
1442 f = search_getfilename(globhandle, i);
1443 precache_playermodel(f);
1445 search_end(globhandle);
1450 // gamemode related things
1451 precache_model ("models/misc/chatbubble.spr");
1454 precache_model ("models/runematch/curse.mdl");
1455 precache_model ("models/runematch/rune.mdl");
1458 #ifdef TTURRETS_ENABLED
1459 if (autocvar_g_turrets)
1463 // Precache all player models if desired
1464 if (autocvar_sv_precacheplayermodels)
1466 PrecachePlayerSounds("sound/player/default.sounds");
1467 precache_all_playermodels("models/player/*.zym");
1468 precache_all_playermodels("models/player/*.dpm");
1469 precache_all_playermodels("models/player/*.md3");
1470 precache_all_playermodels("models/player/*.psk");
1471 precache_all_playermodels("models/player/*.iqm");
1474 if (autocvar_sv_defaultcharacter)
1477 s = autocvar_sv_defaultplayermodel_red;
1479 precache_playermodel(s);
1480 s = autocvar_sv_defaultplayermodel_blue;
1482 precache_playermodel(s);
1483 s = autocvar_sv_defaultplayermodel_yellow;
1485 precache_playermodel(s);
1486 s = autocvar_sv_defaultplayermodel_pink;
1488 precache_playermodel(s);
1489 s = autocvar_sv_defaultplayermodel;
1491 precache_playermodel(s);
1496 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
1497 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
1500 // gore and miscellaneous sounds
1501 //precache_sound ("misc/h2ohit.wav");
1502 precache_model ("models/hook.md3");
1503 precache_sound ("misc/armorimpact.wav");
1504 precache_sound ("misc/bodyimpact1.wav");
1505 precache_sound ("misc/bodyimpact2.wav");
1506 precache_sound ("misc/gib.wav");
1507 precache_sound ("misc/gib_splat01.wav");
1508 precache_sound ("misc/gib_splat02.wav");
1509 precache_sound ("misc/gib_splat03.wav");
1510 precache_sound ("misc/gib_splat04.wav");
1511 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
1512 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
1513 precache_sound ("misc/null.wav");
1514 precache_sound ("misc/spawn.wav");
1515 precache_sound ("misc/talk.wav");
1516 precache_sound ("misc/teleport.wav");
1517 precache_sound ("misc/poweroff.wav");
1518 precache_sound ("player/lava.wav");
1519 precache_sound ("player/slime.wav");
1522 precache_sound ("misc/jetpack_fly.wav");
1524 precache_model ("models/sprites/0.spr32");
1525 precache_model ("models/sprites/1.spr32");
1526 precache_model ("models/sprites/2.spr32");
1527 precache_model ("models/sprites/3.spr32");
1528 precache_model ("models/sprites/4.spr32");
1529 precache_model ("models/sprites/5.spr32");
1530 precache_model ("models/sprites/6.spr32");
1531 precache_model ("models/sprites/7.spr32");
1532 precache_model ("models/sprites/8.spr32");
1533 precache_model ("models/sprites/9.spr32");
1534 precache_model ("models/sprites/10.spr32");
1536 // common weapon precaches
1537 precache_sound ("weapons/reload.wav"); // until weapons have individual reload sounds, precache the reload sound here
1538 precache_sound ("weapons/weapon_switch.wav");
1539 precache_sound ("weapons/weaponpickup.wav");
1540 precache_sound ("weapons/unavailable.wav");
1541 precache_sound ("weapons/dryfire.wav");
1542 if (g_grappling_hook)
1544 precache_sound ("weapons/hook_fire.wav"); // hook
1545 precache_sound ("weapons/hook_impact.wav"); // hook
1548 if(autocvar_sv_precacheweapons)
1550 //precache weapon models/sounds
1553 while (wep <= WEP_LAST)
1555 weapon_action(wep, WR_PRECACHE);
1560 precache_model("models/elaser.mdl");
1561 precache_model("models/laser.mdl");
1562 precache_model("models/ebomb.mdl");
1565 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
1567 if (!self.noise && self.music) // quake 3 uses the music field
1568 self.noise = self.music;
1570 // plays music for the level if there is any
1573 precache_sound (self.noise);
1574 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
1579 // WARNING: this kills the trace globals
1580 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
1581 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
1583 #define INITPRIO_FIRST 0
1584 #define INITPRIO_GAMETYPE 0
1585 #define INITPRIO_GAMETYPE_FALLBACK 1
1586 #define INITPRIO_FINDTARGET 10
1587 #define INITPRIO_DROPTOFLOOR 20
1588 #define INITPRIO_SETLOCATION 90
1589 #define INITPRIO_LINKDOORS 91
1590 #define INITPRIO_LAST 99
1592 .void(void) initialize_entity;
1593 .float initialize_entity_order;
1594 .entity initialize_entity_next;
1595 entity initialize_entity_first;
1597 void make_safe_for_remove(entity e)
1599 if (e.initialize_entity)
1601 entity ent, prev = world;
1602 for (ent = initialize_entity_first; ent; )
1604 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
1606 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
1607 // skip it in linked list
1610 prev.initialize_entity_next = ent.initialize_entity_next;
1611 ent = prev.initialize_entity_next;
1615 initialize_entity_first = ent.initialize_entity_next;
1616 ent = initialize_entity_first;
1622 ent = ent.initialize_entity_next;
1628 void objerror(string s)
1630 make_safe_for_remove(self);
1631 builtin_objerror(s);
1634 .float remove_except_protected_forbidden;
1635 void remove_except_protected(entity e)
1637 if(e.remove_except_protected_forbidden)
1638 error("not allowed to remove this at this point");
1642 void remove_unsafely(entity e)
1644 if(e.classname == "spike")
1645 error("Removing spikes is forbidden (crylink bug), please report");
1649 void remove_safely(entity e)
1651 make_safe_for_remove(e);
1655 void InitializeEntity(entity e, void(void) func, float order)
1659 if (!e || e.initialize_entity)
1661 // make a proxy initializer entity
1665 e.classname = "initialize_entity";
1669 e.initialize_entity = func;
1670 e.initialize_entity_order = order;
1672 cur = initialize_entity_first;
1676 if (!cur || cur.initialize_entity_order > order)
1678 // insert between prev and cur
1680 prev.initialize_entity_next = e;
1682 initialize_entity_first = e;
1683 e.initialize_entity_next = cur;
1687 cur = cur.initialize_entity_next;
1690 void InitializeEntitiesRun()
1693 startoflist = initialize_entity_first;
1694 initialize_entity_first = world;
1695 remove = remove_except_protected;
1696 for (self = startoflist; self; self = self.initialize_entity_next)
1698 self.remove_except_protected_forbidden = 1;
1700 for (self = startoflist; self; )
1703 var void(void) func;
1704 e = self.initialize_entity_next;
1705 func = self.initialize_entity;
1706 self.initialize_entity_order = 0;
1707 self.initialize_entity = func_null;
1708 self.initialize_entity_next = world;
1709 self.remove_except_protected_forbidden = 0;
1710 if (self.classname == "initialize_entity")
1714 builtin_remove(self);
1717 //dprint("Delayed initialization: ", self.classname, "\n");
1718 if(func != func_null)
1723 backtrace(strcat("Null function in: ", self.classname, "\n"));
1727 remove = remove_unsafely;
1730 .float uncustomizeentityforclient_set;
1731 .void(void) uncustomizeentityforclient;
1732 void(void) SUB_Nullpointer = #0;
1733 void UncustomizeEntitiesRun()
1737 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
1738 self.uncustomizeentityforclient();
1741 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
1743 e.customizeentityforclient = customizer;
1744 e.uncustomizeentityforclient = uncustomizer;
1745 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
1749 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
1752 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
1756 if (e.classname == "")
1757 e.classname = "net_linked";
1759 if (e.model == "" || self.modelindex == 0)
1763 setmodel(e, "null");
1767 e.SendEntity = sendfunc;
1768 e.SendFlags = 0xFFFFFF;
1771 e.effects |= EF_NODEPTHTEST;
1775 e.nextthink = time + dt;
1776 e.think = SUB_Remove;
1780 void adaptor_think2touch()
1789 void adaptor_think2use()
1801 void adaptor_think2use_hittype_splash() // for timed projectile detonation
1803 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
1804 self.projectiledeathtype |= HITTYPE_SPLASH;
1805 adaptor_think2use();
1808 // deferred dropping
1809 void DropToFloor_Handler()
1811 builtin_droptofloor();
1812 self.dropped_origin = self.origin;
1817 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
1822 float trace_hits_box_a0, trace_hits_box_a1;
1824 float trace_hits_box_1d(float end, float thmi, float thma)
1828 // just check if x is in range
1836 // do the trace with respect to x
1837 // 0 -> end has to stay in thmi -> thma
1838 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1839 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1840 if (trace_hits_box_a0 > trace_hits_box_a1)
1846 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1851 // now it is a trace from 0 to end
1853 trace_hits_box_a0 = 0;
1854 trace_hits_box_a1 = 1;
1856 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
1858 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
1860 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
1866 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
1868 return trace_hits_box(start, end, thmi - ma, thma - mi);
1871 float SUB_NoImpactCheck()
1873 // zero hitcontents = this is not the real impact, but either the
1874 // mirror-impact of something hitting the projectile instead of the
1875 // projectile hitting the something, or a touchareagrid one. Neither of
1876 // these stop the projectile from moving, so...
1877 if(trace_dphitcontents == 0)
1879 //dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
1880 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)));
1883 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1885 if (other == world && self.size != '0 0 0')
1888 tic = self.velocity * sys_frametime;
1889 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
1890 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
1891 if (trace_fraction >= 1)
1893 dprint("Odd... did not hit...?\n");
1895 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
1897 dprint("Detected and prevented the sky-grapple bug.\n");
1905 #define SUB_OwnerCheck() (other && (other == self.owner))
1907 void RemoveGrapplingHook(entity pl);
1908 void W_Crylink_Dequeue(entity e);
1909 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
1911 if(SUB_OwnerCheck())
1913 if(SUB_NoImpactCheck())
1915 if(self.classname == "grapplinghook")
1916 RemoveGrapplingHook(self.realowner);
1917 else if(self.classname == "spike")
1919 W_Crylink_Dequeue(self);
1926 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
1927 UpdateCSQCProjectile(self);
1930 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
1932 #define ITEM_TOUCH_NEEDKILL() (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY))
1933 #define ITEM_DAMAGE_NEEDKILL(dt) (((dt) == DEATH_HURTTRIGGER) || ((dt) == DEATH_SLIME) || ((dt) == DEATH_LAVA) || ((dt) == DEATH_SWAMP))
1935 void URI_Get_Callback(float id, float status, string data)
1937 if(url_URI_Get_Callback(id, status, data))
1941 else if (id == URI_GET_DISCARD)
1945 else if (id >= URI_GET_CURL && id <= URI_GET_CURL_END)
1948 Curl_URI_Get_Callback(id, status, data);
1950 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
1953 OnlineBanList_URI_Get_Callback(id, status, data);
1957 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
1961 string uid2name(string myuid) {
1963 s = db_get(ServerProgsDB, strcat("/uid2name/", myuid));
1965 // FIXME remove this later after 0.6 release
1966 // convert old style broken records to correct style
1969 s = db_get(ServerProgsDB, strcat("uid2name", myuid));
1972 db_put(ServerProgsDB, strcat("/uid2name/", myuid), s);
1973 db_put(ServerProgsDB, strcat("uid2name", myuid), "");
1978 s = "^1Unregistered Player";
1982 float race_readTime(string map, float pos)
1990 return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
1993 string race_readUID(string map, float pos)
2001 return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
2004 float race_readPos(string map, float t) {
2006 for (i = 1; i <= RANKINGS_CNT; ++i)
2007 if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
2010 return 0; // pos is zero if unranked
2013 void race_writeTime(string map, float t, string myuid)
2022 newpos = race_readPos(map, t);
2024 float i, prevpos = 0;
2025 for(i = 1; i <= RANKINGS_CNT; ++i)
2027 if(race_readUID(map, i) == myuid)
2030 if (prevpos) { // player improved his existing record, only have to iterate on ranks between new and old recs
2031 for (i = prevpos; i > newpos; --i) {
2032 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
2033 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
2035 } else { // player has no ranked record yet
2036 for (i = RANKINGS_CNT; i > newpos; --i) {
2037 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1)));
2038 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1));
2042 // store new time itself
2043 db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t));
2044 db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid);
2047 string race_readName(string map, float pos)
2055 return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
2058 string race_placeName(float pos) {
2059 if(floor((mod(pos, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
2061 if(mod(pos, 10) == 1)
2062 return strcat(ftos(pos), "st");
2063 else if(mod(pos, 10) == 2)
2064 return strcat(ftos(pos), "nd");
2065 else if(mod(pos, 10) == 3)
2066 return strcat(ftos(pos), "rd");
2068 return strcat(ftos(pos), "th");
2071 return strcat(ftos(pos), "th");
2074 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
2077 vector start, org, delta, end, enddown, mstart;
2080 m = e.dphitcontentsmask;
2081 e.dphitcontentsmask = goodcontents | badcontents;
2084 delta = world.maxs - world.mins;
2088 for (i = 0; i < attempts; ++i)
2090 start_x = org_x + random() * delta_x;
2091 start_y = org_y + random() * delta_y;
2092 start_z = org_z + random() * delta_z;
2094 // rule 1: start inside world bounds, and outside
2095 // solid, and don't start from somewhere where you can
2096 // fall down to evil
2097 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
2098 if (trace_fraction >= 1)
2100 if (trace_startsolid)
2102 if (trace_dphitcontents & badcontents)
2104 if (trace_dphitq3surfaceflags & badsurfaceflags)
2107 // rule 2: if we are too high, lower the point
2108 if (trace_fraction * delta_z > maxaboveground)
2109 start = trace_endpos + '0 0 1' * maxaboveground;
2110 enddown = trace_endpos;
2112 // rule 3: make sure we aren't outside the map. This only works
2113 // for somewhat well formed maps. A good rule of thumb is that
2114 // the map should have a convex outside hull.
2115 // these can be traceLINES as we already verified the starting box
2116 mstart = start + 0.5 * (e.mins + e.maxs);
2117 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
2118 if (trace_fraction >= 1)
2120 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
2121 if (trace_fraction >= 1)
2123 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
2124 if (trace_fraction >= 1)
2126 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
2127 if (trace_fraction >= 1)
2129 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
2130 if (trace_fraction >= 1)
2133 // rule 4: we must "see" some spawnpoint
2134 for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
2135 if(checkpvs(mstart, sp))
2139 for(sp = world; (sp = findflags(sp, flags, FL_ITEM)); )
2140 if(checkpvs(mstart, sp))
2146 // find a random vector to "look at"
2147 end_x = org_x + random() * delta_x;
2148 end_y = org_y + random() * delta_y;
2149 end_z = org_z + random() * delta_z;
2150 end = start + normalize(end - start) * vlen(delta);
2152 // rule 4: start TO end must not be too short
2153 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
2154 if (trace_startsolid)
2156 if (trace_fraction < minviewdistance / vlen(delta))
2159 // rule 5: don't want to look at sky
2160 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
2163 // rule 6: we must not end up in trigger_hurt
2164 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
2170 e.dphitcontentsmask = m;
2174 setorigin(e, start);
2175 e.angles = vectoangles(end - start);
2176 dprint("Needed ", ftos(i + 1), " attempts\n");
2183 float zcurveparticles_effectno;
2184 vector zcurveparticles_start;
2185 float zcurveparticles_spd;
2187 void endzcurveparticles()
2189 if(zcurveparticles_effectno)
2192 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
2194 zcurveparticles_effectno = 0;
2197 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
2199 spd = bound(0, floor(spd / 16), 32767);
2200 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
2202 endzcurveparticles();
2203 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
2204 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
2205 WriteShort(MSG_BROADCAST, effectno);
2206 WriteCoord(MSG_BROADCAST, start_x);
2207 WriteCoord(MSG_BROADCAST, start_y);
2208 WriteCoord(MSG_BROADCAST, start_z);
2209 zcurveparticles_effectno = effectno;
2210 zcurveparticles_start = start;
2213 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
2214 WriteCoord(MSG_BROADCAST, end_x);
2215 WriteCoord(MSG_BROADCAST, end_y);
2216 WriteCoord(MSG_BROADCAST, end_z);
2217 WriteCoord(MSG_BROADCAST, end_dz);
2218 zcurveparticles_spd = spd;
2221 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
2224 vector vecxy, velxy;
2226 vecxy = end - start;
2231 if (vlen(velxy) < 0.000001 * fabs(vel_z))
2233 endzcurveparticles();
2234 trailparticles(world, effectno, start, end);
2238 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
2239 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
2242 void write_recordmarker(entity pl, float tstart, float dt)
2244 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
2246 // also write a marker into demo files for demotc-race-record-extractor to find
2249 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
2250 " ", ftos(tstart), " ", ftos(dt), "\n"));
2253 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter, float algn)
2266 if(allowcenter) // 2: allow center handedness
2279 if(allowcenter) // 2: allow center handedness
2295 vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float algn)
2300 if (autocvar_g_shootfromeye)
2313 else if (autocvar_g_shootfromcenter)
2318 else if ((s = autocvar_g_shootfromfixedorigin) != "")
2328 else if (autocvar_g_shootfromclient)
2330 vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn);
2335 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
2337 return shotorg_adjust_values(vecs, y_is_right, visual, self.owner.cvar_cl_gunalign);
2341 void attach_sameorigin(entity e, entity to, string tag)
2343 vector org, t_forward, t_left, t_up, e_forward, e_up;
2346 org = e.origin - gettaginfo(to, gettagindex(to, tag));
2347 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
2348 t_forward = v_forward * tagscale;
2349 t_left = v_right * -tagscale;
2350 t_up = v_up * tagscale;
2352 e.origin_x = org * t_forward;
2353 e.origin_y = org * t_left;
2354 e.origin_z = org * t_up;
2356 // current forward and up directions
2357 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2358 e.angles = AnglesTransform_FromVAngles(e.angles);
2360 e.angles = AnglesTransform_FromAngles(e.angles);
2361 fixedmakevectors(e.angles);
2363 // untransform forward, up!
2364 e_forward_x = v_forward * t_forward;
2365 e_forward_y = v_forward * t_left;
2366 e_forward_z = v_forward * t_up;
2367 e_up_x = v_up * t_forward;
2368 e_up_y = v_up * t_left;
2369 e_up_z = v_up * t_up;
2371 e.angles = fixedvectoangles2(e_forward, e_up);
2372 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2373 e.angles = AnglesTransform_ToVAngles(e.angles);
2375 e.angles = AnglesTransform_ToAngles(e.angles);
2377 setattachment(e, to, tag);
2378 setorigin(e, e.origin);
2381 void detach_sameorigin(entity e)
2384 org = gettaginfo(e, 0);
2385 e.angles = fixedvectoangles2(v_forward, v_up);
2386 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
2387 e.angles = AnglesTransform_ToVAngles(e.angles);
2389 e.angles = AnglesTransform_ToAngles(e.angles);
2391 setattachment(e, world, "");
2392 setorigin(e, e.origin);
2395 void follow_sameorigin(entity e, entity to)
2397 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
2398 e.aiment = to; // make the hole follow bmodel
2399 e.punchangle = to.angles; // the original angles of bmodel
2400 e.view_ofs = e.origin - to.origin; // relative origin
2401 e.v_angle = e.angles - to.angles; // relative angles
2404 void unfollow_sameorigin(entity e)
2406 e.movetype = MOVETYPE_NONE;
2409 entity gettaginfo_relative_ent;
2410 vector gettaginfo_relative(entity e, float tag)
2412 if (!gettaginfo_relative_ent)
2414 gettaginfo_relative_ent = spawn();
2415 gettaginfo_relative_ent.effects = EF_NODRAW;
2417 gettaginfo_relative_ent.model = e.model;
2418 gettaginfo_relative_ent.modelindex = e.modelindex;
2419 gettaginfo_relative_ent.frame = e.frame;
2420 return gettaginfo(gettaginfo_relative_ent, tag);
2423 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
2427 if (pl.soundentity.cnt & p)
2429 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
2430 pl.soundentity.cnt |= p;
2433 void SoundEntity_StopSound(entity pl, float chan)
2437 if (pl.soundentity.cnt & p)
2439 stopsoundto(MSG_ALL, pl.soundentity, chan);
2440 pl.soundentity.cnt &~= p;
2444 void SoundEntity_Attach(entity pl)
2446 pl.soundentity = spawn();
2447 pl.soundentity.classname = "soundentity";
2448 pl.soundentity.owner = pl;
2449 setattachment(pl.soundentity, pl, "");
2450 setmodel(pl.soundentity, "null");
2453 void SoundEntity_Detach(entity pl)
2456 for (i = 0; i <= 7; ++i)
2457 SoundEntity_StopSound(pl, i);
2462 float modeleffect_SendEntity(entity to, float sf)
2465 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
2468 if(self.velocity != '0 0 0')
2470 if(self.angles != '0 0 0')
2472 if(self.avelocity != '0 0 0')
2475 WriteByte(MSG_ENTITY, f);
2476 WriteShort(MSG_ENTITY, self.modelindex);
2477 WriteByte(MSG_ENTITY, self.skin);
2478 WriteByte(MSG_ENTITY, self.frame);
2479 WriteCoord(MSG_ENTITY, self.origin_x);
2480 WriteCoord(MSG_ENTITY, self.origin_y);
2481 WriteCoord(MSG_ENTITY, self.origin_z);
2484 WriteCoord(MSG_ENTITY, self.velocity_x);
2485 WriteCoord(MSG_ENTITY, self.velocity_y);
2486 WriteCoord(MSG_ENTITY, self.velocity_z);
2490 WriteCoord(MSG_ENTITY, self.angles_x);
2491 WriteCoord(MSG_ENTITY, self.angles_y);
2492 WriteCoord(MSG_ENTITY, self.angles_z);
2496 WriteCoord(MSG_ENTITY, self.avelocity_x);
2497 WriteCoord(MSG_ENTITY, self.avelocity_y);
2498 WriteCoord(MSG_ENTITY, self.avelocity_z);
2500 WriteShort(MSG_ENTITY, self.scale * 256.0);
2501 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
2502 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
2503 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
2504 WriteByte(MSG_ENTITY, self.alpha * 255.0);
2509 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)
2514 e.classname = "modeleffect";
2522 e.teleport_time = t1;
2526 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2530 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
2533 sz = max(e.scale, e.scale2);
2534 setsize(e, e.mins * sz, e.maxs * sz);
2535 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
2538 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
2540 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
2543 float randombit(float bits)
2545 if not(bits & (bits-1)) // this ONLY holds for powers of two!
2554 for(f = 1; f <= bits; f *= 2)
2563 r = (r - 1) / (n - 1);
2570 float randombits(float bits, float k, float error_return)
2574 while(k > 0 && bits != r)
2576 r += randombit(bits - r);
2585 void randombit_test(float bits, float iter)
2589 print(ftos(randombit(bits)), "\n");
2594 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
2596 if(halflifedist > 0)
2597 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
2598 else if(halflifedist < 0)
2599 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
2608 #define cvar_string_normal builtin_cvar_string
2609 #define cvar_normal builtin_cvar
2611 string cvar_string_normal(string n)
2613 if not(cvar_type(n) & 1)
2614 backtrace(strcat("Attempt to access undefined cvar: ", n));
2615 return builtin_cvar_string(n);
2618 float cvar_normal(string n)
2620 return stof(cvar_string_normal(n));
2623 #define cvar_set_normal builtin_cvar_set
2631 oself.think = SUB_Remove;
2632 oself.nextthink = time;
2638 Execute func() after time + fdelay.
2639 self when func is executed = self when defer is called
2641 void defer(float fdelay, void() func)
2648 e.think = defer_think;
2649 e.nextthink = time + fdelay;
2652 .string aiment_classname;
2653 .float aiment_deadflag;
2654 void SetMovetypeFollow(entity ent, entity e)
2656 // FIXME this may not be warpzone aware
2657 ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
2658 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.
2659 ent.aiment = e; // make the hole follow bmodel
2660 ent.punchangle = e.angles; // the original angles of bmodel
2661 ent.view_ofs = ent.origin - e.origin; // relative origin
2662 ent.v_angle = ent.angles - e.angles; // relative angles
2663 ent.aiment_classname = strzone(e.classname);
2664 ent.aiment_deadflag = e.deadflag;
2666 void UnsetMovetypeFollow(entity ent)
2668 ent.movetype = MOVETYPE_FLY;
2669 PROJECTILE_MAKETRIGGER(ent);
2672 float LostMovetypeFollow(entity ent)
2675 if(ent.movetype != MOVETYPE_FOLLOW)
2681 if(ent.aiment.classname != ent.aiment_classname)
2683 if(ent.aiment.deadflag != ent.aiment_deadflag)
2689 float isPushable(entity e)
2698 case "droppedweapon":
2699 case "keepawayball":
2700 case "nexball_basketball":
2701 case "nexball_football":
2703 case "bullet": // antilagged bullets can't hit this either
2706 if (e.projectiledeathtype)
2711 void dedicated_print(string input) // print(), but only print if the server is not local
2713 if not(server_is_local) { print(input); }