1 var void remove(entity e);
\r
2 void objerror(string s);
\r
4 .vector dropped_origin;
\r
6 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
\r
7 void crosshair_trace(entity pl)
\r
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));
\r
11 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
\r
12 void WarpZone_crosshair_trace(entity pl)
\r
14 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));
\r
17 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
\r
18 void() spawnpoint_use;
\r
19 float race_GetTime(float pos);
\r
20 string race_GetName(float pos);
\r
21 string race_PlaceName(float pos);
\r
22 string GetMapname();
\r
23 string ColoredTeamName(float t);
\r
25 string admin_name(void)
\r
27 if(cvar_string("sv_adminnick") != "")
\r
28 return cvar_string("sv_adminnick");
\r
30 return "SERVER ADMIN";
\r
33 float DistributeEvenly_amount;
\r
34 float DistributeEvenly_totalweight;
\r
35 void DistributeEvenly_Init(float amount, float totalweight)
\r
37 if (DistributeEvenly_amount)
\r
39 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
\r
40 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
\r
42 if (totalweight == 0)
\r
43 DistributeEvenly_amount = 0;
\r
45 DistributeEvenly_amount = amount;
\r
46 DistributeEvenly_totalweight = totalweight;
\r
48 float DistributeEvenly_Get(float weight)
\r
53 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
\r
54 DistributeEvenly_totalweight -= weight;
\r
55 DistributeEvenly_amount -= f;
\r
59 #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
\r
62 string STR_PLAYER = "player";
\r
63 string STR_SPECTATOR = "spectator";
\r
64 string STR_OBSERVER = "observer";
\r
67 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
\r
68 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
69 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
\r
70 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
72 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
\r
73 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
\r
74 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
75 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
\r
76 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
\r
79 // copies a string to a tempstring (so one can strunzone it)
\r
80 string strcat1(string s) = #115; // FRIK_FILE
\r
85 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
\r
87 local float nPlayerHealth = rint(enPlayer.health);
\r
88 local float nPlayerArmor = rint(enPlayer.armorvalue);
\r
89 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
\r
90 local float nPlayerPing = rint(enPlayer.ping);
\r
91 local string strPlayerPingColor;
\r
92 local string strMessage;
\r
93 if(nPlayerPing >= 150)
\r
94 strPlayerPingColor = "^1";
\r
96 strPlayerPingColor = "^2";
\r
98 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
\r
99 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
\r
101 if(cvar("sv_fragmessage_information_ping")) {
\r
102 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
\r
103 strMessage = strcat(strMessage, "\n^7(^2Bot");
\r
105 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
\r
106 if(cvar("sv_fragmessage_information_handicap"))
\r
107 if(cvar("sv_fragmessage_information_handicap") == 2)
\r
108 if(nPlayerHandicap <= 1)
\r
109 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
\r
111 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
112 else if not(nPlayerHandicap <= 1)
\r
113 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
115 strMessage = strcat(strMessage, "^7)");
\r
116 } else if(cvar("sv_fragmessage_information_handicap")) {
\r
117 if(cvar("sv_fragmessage_information_handicap") == 2)
\r
118 if(nPlayerHandicap <= 1)
\r
119 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
\r
121 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
122 else if(nPlayerHandicap > 1)
\r
123 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
127 void bcenterprint(string s)
\r
129 // TODO replace by MSG_ALL (would show it to spectators too, though)?
\r
131 FOR_EACH_PLAYER(head)
\r
132 if (clienttype(head) == CLIENTTYPE_REAL)
\r
133 centerprint(head, s);
\r
136 void GameLogEcho(string s)
\r
141 if (cvar("sv_eventlog_files"))
\r
145 logfile_open = TRUE;
\r
146 matches = cvar("sv_eventlog_files_counter") + 1;
\r
147 cvar_set("sv_eventlog_files_counter", ftos(matches));
\r
148 fn = ftos(matches);
\r
149 if (strlen(fn) < 8)
\r
150 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
\r
151 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
\r
152 logfile = fopen(fn, FILE_APPEND);
\r
153 fputs(logfile, ":logversion:3\n");
\r
157 if (cvar("sv_eventlog_files_timestamps"))
\r
158 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
\r
160 fputs(logfile, strcat(s, "\n"));
\r
163 if (cvar("sv_eventlog_console"))
\r
172 // will be opened later
\r
175 void GameLogClose()
\r
177 if (logfile_open && logfile >= 0)
\r
184 vector PL_VIEW_OFS;
\r
187 vector PL_CROUCH_VIEW_OFS;
\r
188 vector PL_CROUCH_MIN;
\r
189 vector PL_CROUCH_MAX;
\r
191 float spawnpoint_nag;
\r
192 void relocate_spawnpoint()
\r
194 PL_VIEW_OFS = stov(cvar_string("sv_player_viewoffset"));
\r
195 PL_MIN = stov(cvar_string("sv_player_mins"));
\r
196 PL_MAX = stov(cvar_string("sv_player_maxs"));
\r
197 PL_CROUCH_VIEW_OFS = stov(cvar_string("sv_player_crouch_viewoffset"));
\r
198 PL_CROUCH_MIN = stov(cvar_string("sv_player_crouch_mins"));
\r
199 PL_CROUCH_MAX = stov(cvar_string("sv_player_crouch_maxs"));
\r
201 // nudge off the floor
\r
202 setorigin(self, self.origin + '0 0 1');
\r
204 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
\r
205 if (trace_startsolid)
\r
209 self.mins = PL_MIN;
\r
210 self.maxs = PL_MAX;
\r
211 if (!move_out_of_solid(self))
\r
212 objerror("could not get out of solid at all!");
\r
213 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
\r
214 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
\r
215 print(" ", ftos(self.origin_y - o_y));
\r
216 print(" ", ftos(self.origin_z - o_z), "'\n");
\r
217 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
\r
219 if (!spawnpoint_nag)
\r
220 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
\r
221 spawnpoint_nag = 1;
\r
225 setorigin(self, o);
\r
226 self.mins = self.maxs = '0 0 0';
\r
227 objerror("player spawn point in solid, mapper sucks!\n");
\r
232 if (cvar("g_spawnpoints_autodrop"))
\r
234 setsize(self, PL_MIN, PL_MAX);
\r
238 self.use = spawnpoint_use;
\r
239 self.team_saved = self.team;
\r
243 if (have_team_spawns != 0)
\r
245 have_team_spawns = 1;
\r
247 if (cvar("r_showbboxes"))
\r
249 // show where spawnpoints point at too
\r
250 makevectors(self.angles);
\r
253 e.classname = "info_player_foo";
\r
254 setorigin(e, self.origin + v_forward * 24);
\r
255 setsize(e, '-8 -8 -8', '8 8 8');
\r
256 e.solid = SOLID_TRIGGER;
\r
260 #define strstr strstrofs
\r
262 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
\r
263 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
\r
264 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
\r
265 // BE CONSTANT OR strzoneD!
\r
266 float strstr(string haystack, string needle, float offset)
\r
270 len = strlen(needle);
\r
271 endpos = strlen(haystack) - len;
\r
272 while(offset <= endpos)
\r
274 found = substring(haystack, offset, len);
\r
275 if(found == needle)
\r
277 offset = offset + 1;
\r
283 float NUM_NEAREST_ENTITIES = 4;
\r
284 entity nearest_entity[NUM_NEAREST_ENTITIES];
\r
285 float nearest_length[NUM_NEAREST_ENTITIES];
\r
286 entity findnearest(vector point, .string field, string value, vector axismod)
\r
297 localhead = find(world, field, value);
\r
300 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
\r
301 dist = localhead.oldorigin;
\r
303 dist = localhead.origin;
\r
304 dist = dist - point;
\r
305 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
\r
308 for (i = 0; i < num_nearest; ++i)
\r
310 if (len < nearest_length[i])
\r
314 // now i tells us where to insert at
\r
315 // INSERTION SORT! YOU'VE SEEN IT! RUN!
\r
316 if (i < NUM_NEAREST_ENTITIES)
\r
318 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
\r
320 nearest_length[j + 1] = nearest_length[j];
\r
321 nearest_entity[j + 1] = nearest_entity[j];
\r
323 nearest_length[i] = len;
\r
324 nearest_entity[i] = localhead;
\r
325 if (num_nearest < NUM_NEAREST_ENTITIES)
\r
326 num_nearest = num_nearest + 1;
\r
329 localhead = find(localhead, field, value);
\r
332 // now use the first one from our list that we can see
\r
333 for (i = 0; i < num_nearest; ++i)
\r
335 traceline(point, nearest_entity[i].origin, TRUE, world);
\r
336 if (trace_fraction == 1)
\r
340 dprint("Nearest point (");
\r
341 dprint(nearest_entity[0].netname);
\r
342 dprint(") is not visible, using a visible one.\n");
\r
344 return nearest_entity[i];
\r
348 if (num_nearest == 0)
\r
351 dprint("Not seeing any location point, using nearest as fallback.\n");
\r
353 dprint("Candidates were: ");
\r
354 for(j = 0; j < num_nearest; ++j)
\r
358 dprint(nearest_entity[j].netname);
\r
363 return nearest_entity[0];
\r
366 void spawnfunc_target_location()
\r
368 self.classname = "target_location";
\r
369 // location name in netname
\r
370 // eventually support: count, teamgame selectors, line of sight?
\r
373 void spawnfunc_info_location()
\r
375 self.classname = "target_location";
\r
376 self.message = self.netname;
\r
379 string NearestLocation(vector p)
\r
384 loc = findnearest(p, classname, "target_location", '1 1 1');
\r
391 loc = findnearest(p, target, "###item###", '1 1 4');
\r
398 string formatmessage(string msg)
\r
405 string replacement;
\r
409 WarpZone_crosshair_trace(self);
\r
410 cursor = trace_endpos;
\r
411 cursor_ent = trace_ent;
\r
415 break; // too many replacements
\r
418 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
\r
419 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
\r
432 replacement = substring(msg, p, 2);
\r
433 escape = substring(msg, p + 1, 1);
\r
437 else if (escape == "\\")
\r
438 replacement = "\\";
\r
439 else if (escape == "n")
\r
440 replacement = "\n";
\r
441 else if (escape == "a")
\r
442 replacement = ftos(floor(self.armorvalue));
\r
443 else if (escape == "h")
\r
444 replacement = ftos(floor(self.health));
\r
445 else if (escape == "l")
\r
446 replacement = NearestLocation(self.origin);
\r
447 else if (escape == "y")
\r
448 replacement = NearestLocation(cursor);
\r
449 else if (escape == "d")
\r
450 replacement = NearestLocation(self.death_origin);
\r
451 else if (escape == "w") {
\r
455 wep = self.switchweapon;
\r
458 replacement = W_Name(wep);
\r
459 } else if (escape == "W") {
\r
460 replacement = "batteries"; // ;)
\r
461 } else if (escape == "x") {
\r
462 replacement = cursor_ent.netname;
\r
463 if (!replacement || !cursor_ent)
\r
464 replacement = "nothing";
\r
465 } else if (escape == "p") {
\r
466 if (self.last_selected_player)
\r
467 replacement = self.last_selected_player.netname;
\r
469 replacement = "(nobody)";
\r
470 } else if (escape == "s")
\r
471 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
\r
472 else if (escape == "S")
\r
473 replacement = ftos(vlen(self.velocity));
\r
474 else if (escape == "v") {
\r
475 float weapon_number;
\r
476 local entity stats;
\r
478 if(self.classname == "spectator")
\r
479 stats = self.enemy;
\r
483 weapon_number = stats.weapon;
\r
485 if (!weapon_number)
\r
486 weapon_number = stats.switchweapon;
\r
488 if (!weapon_number)
\r
489 weapon_number = stats.cnt;
\r
491 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
\r
492 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
\r
494 replacement = "~"; // or something to indicate NULL, not available
\r
497 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
\r
498 p = p + strlen(replacement);
\r
503 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
\r
504 return (value == 0) ? FALSE : TRUE;
\r
512 0: sends the request
\r
513 >0: receives a cvar from name=argv(f) value=argv(f+1)
\r
515 void GetCvars_handleString(string thisname, float f, .string field, string name)
\r
520 strunzone(self.field);
\r
521 self.field = string_null;
\r
525 if (thisname == name)
\r
528 strunzone(self.field);
\r
529 self.field = strzone(argv(f + 1));
\r
533 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
535 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
\r
537 GetCvars_handleString(thisname, f, field, name);
\r
538 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
\r
539 if (thisname == name)
\r
542 s = func(strcat1(self.field));
\r
543 if (s != self.field)
\r
545 strunzone(self.field);
\r
546 self.field = strzone(s);
\r
550 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
\r
557 if (thisname == name)
\r
558 self.field = stof(argv(f + 1));
\r
561 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
563 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
\r
570 if (thisname == name)
\r
574 self.field = stof(argv(f + 1));
\r
583 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
586 string W_FixWeaponOrder_ForceComplete(string s);
\r
587 string W_FixWeaponOrder_AllowIncomplete(string s);
\r
588 float w_getbestweapon(entity e);
\r
589 void GetCvars(float f)
\r
593 s = strcat1(argv(f));
\r
594 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
\r
595 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
\r
596 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
\r
597 GetCvars_handleString(s, f, cvar_g_voretournamentversion, "g_voretournamentversion");
\r
598 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
\r
599 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
\r
600 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
\r
601 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
\r
602 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
\r
603 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
\r
604 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
\r
605 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
\r
606 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
\r
607 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
\r
608 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
\r
609 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
\r
610 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
\r
611 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
\r
612 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
\r
613 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
\r
614 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
\r
615 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
\r
616 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
\r
617 GetCvars_handleFloat(s, f, cvar_chase_active, "chase_active");
\r
618 GetCvars_handleFloat(s, f, cvar_cl_vore_stomachmodel, "cl_vore_stomachmodel");
\r
619 GetCvars_handleFloat(s, f, cvar_cl_vore_cameraspeed, "cl_vore_cameraspeed");
\r
621 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
\r
622 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
\r
624 #ifdef ALLOW_FORCEMODELS
\r
625 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
\r
626 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromvoretournament, "cl_forceplayermodelsfromvoretournament");
\r
628 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
\r
630 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
\r
633 if (s == "cl_weaponpriority")
\r
634 self.switchweapon = w_getbestweapon(self);
\r
638 float fexists(string f)
\r
641 fh = fopen(f, FILE_READ);
\r
648 void backtrace(string msg)
\r
651 dev = cvar("developer");
\r
652 war = cvar("prvm_backtraceforwarnings");
\r
653 cvar_set("developer", "1");
\r
654 cvar_set("prvm_backtraceforwarnings", "1");
\r
656 print("--- CUT HERE ---\nWARNING: ");
\r
659 remove(world); // isn't there any better way to cause a backtrace?
\r
660 print("\n--- CUT UNTIL HERE ---\n");
\r
661 cvar_set("developer", ftos(dev));
\r
662 cvar_set("prvm_backtraceforwarnings", ftos(war));
\r
665 string Team_ColorCode(float teamid)
\r
667 if (teamid == COLOR_TEAM1)
\r
669 else if (teamid == COLOR_TEAM2)
\r
671 else if (teamid == COLOR_TEAM3)
\r
673 else if (teamid == COLOR_TEAM4)
\r
679 string Team_ColorName(float t)
\r
681 // fixme: Search for team entities and get their .netname's!
\r
682 if (t == COLOR_TEAM1)
\r
684 if (t == COLOR_TEAM2)
\r
686 if (t == COLOR_TEAM3)
\r
688 if (t == COLOR_TEAM4)
\r
693 string Team_ColorNameLowerCase(float t)
\r
695 // fixme: Search for team entities and get their .netname's!
\r
696 if (t == COLOR_TEAM1)
\r
698 if (t == COLOR_TEAM2)
\r
700 if (t == COLOR_TEAM3)
\r
702 if (t == COLOR_TEAM4)
\r
707 float ColourToNumber(string team_colour)
\r
709 if (team_colour == "red")
\r
710 return COLOR_TEAM1;
\r
712 if (team_colour == "blue")
\r
713 return COLOR_TEAM2;
\r
715 if (team_colour == "yellow")
\r
716 return COLOR_TEAM3;
\r
718 if (team_colour == "pink")
\r
719 return COLOR_TEAM4;
\r
721 if (team_colour == "auto")
\r
727 float NumberToTeamNumber(float number)
\r
730 return COLOR_TEAM1;
\r
733 return COLOR_TEAM2;
\r
736 return COLOR_TEAM3;
\r
739 return COLOR_TEAM4;
\r
744 #define CENTERPRIO_POINT 1
\r
745 #define CENTERPRIO_SPAM 2
\r
746 #define CENTERPRIO_VOTE 4
\r
747 #define CENTERPRIO_NORMAL 5
\r
748 #define CENTERPRIO_SHIELDING 7
\r
749 #define CENTERPRIO_MAPVOTE 9
\r
750 #define CENTERPRIO_IDLEKICK 50
\r
751 #define CENTERPRIO_ADMIN 99
\r
752 .float centerprint_priority;
\r
753 .float centerprint_expires;
\r
754 void centerprint_atprio(entity e, float prio, string s)
\r
756 if (intermission_running)
\r
757 if (prio < CENTERPRIO_MAPVOTE)
\r
759 if (time > e.centerprint_expires)
\r
760 e.centerprint_priority = 0;
\r
761 if (prio >= e.centerprint_priority)
\r
763 e.centerprint_priority = prio;
\r
764 if (timeoutStatus == 2)
\r
765 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
\r
767 e.centerprint_expires = time + e.cvar_scr_centertime;
\r
768 centerprint_builtin(e, s);
\r
771 void centerprint_expire(entity e, float prio)
\r
773 if (prio == e.centerprint_priority)
\r
775 e.centerprint_priority = 0;
\r
776 centerprint_builtin(e, "");
\r
779 void centerprint(entity e, string s)
\r
781 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
\r
784 // decolorizes and team colors the player name when needed
\r
785 string playername(entity p)
\r
788 if (teams_matter && !intermission_running && p.classname == "player")
\r
790 t = Team_ColorCode(p.team);
\r
791 return strcat(t, strdecolorize(p.netname));
\r
797 vector randompos(vector m1, vector m2)
\r
801 v_x = m2_x * random() + m1_x;
\r
802 v_y = m2_y * random() + m1_y;
\r
803 v_z = m2_z * random() + m1_z;
\r
807 float g_pickup_fuel;
\r
808 float g_pickup_fuel_jetpack;
\r
809 float g_pickup_fuel_max;
\r
810 float g_pickup_armorsmall;
\r
811 float g_pickup_armorsmall_max;
\r
812 float g_pickup_armormedium;
\r
813 float g_pickup_armormedium_max;
\r
814 float g_pickup_armorbig;
\r
815 float g_pickup_armorbig_max;
\r
816 float g_pickup_armorlarge;
\r
817 float g_pickup_armorlarge_max;
\r
818 float g_pickup_healthsmall;
\r
819 float g_pickup_healthsmall_max;
\r
820 float g_pickup_healthmedium;
\r
821 float g_pickup_healthmedium_max;
\r
822 float g_pickup_healthlarge;
\r
823 float g_pickup_healthlarge_max;
\r
824 float g_pickup_healthmega;
\r
825 float g_pickup_healthmega_max;
\r
826 float g_weaponspeedfactor;
\r
827 float g_weaponratefactor;
\r
828 float g_weapondamagefactor;
\r
829 float g_weaponforcefactor;
\r
830 float g_weaponspreadfactor;
\r
832 float start_weapons;
\r
834 float start_ammo_fuel;
\r
835 float start_health;
\r
836 float start_armorvalue;
\r
837 float warmup_start_weapons;
\r
838 float warmup_start_ammo_fuel;
\r
839 float warmup_start_health;
\r
840 float warmup_start_armorvalue;
\r
841 float g_weapon_stay;
\r
842 float g_ghost_items;
\r
844 entity get_weaponinfo(float w);
\r
846 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
\r
848 var float i = weaponinfo.weapon;
\r
853 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
\r
855 if (t < 0) // "default" weapon selection
\r
857 if(g_rpg) // no start weapons in RPG by default
\r
860 t = (i == WEP_GRABBER);
\r
866 void readplayerstartcvars()
\r
871 // initialize starting values for players
\r
874 start_health = cvar("g_balance_health_start");
\r
875 start_armorvalue = cvar("g_balance_armor_start");
\r
879 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
\r
880 start_health = cvar("g_lms_start_health");
\r
881 start_armorvalue = cvar("g_lms_start_armor");
\r
883 else if (cvar("g_use_ammunition"))
\r
885 start_ammo_fuel = cvar("g_start_ammo_fuel");
\r
889 start_ammo_fuel = cvar("g_pickup_fuel_max");
\r
890 start_items |= IT_UNLIMITED_AMMO;
\r
893 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
895 e = get_weaponinfo(i);
\r
896 if(want_weapon("g_start_weapon_", e, FALSE))
\r
898 start_weapons |= e.weapons;
\r
899 weapon_action(e.weapon, WR_PRECACHE);
\r
905 warmup_start_ammo_fuel = start_ammo_fuel;
\r
906 warmup_start_health = start_health;
\r
907 warmup_start_armorvalue = start_armorvalue;
\r
908 warmup_start_weapons = start_weapons;
\r
910 if (cvar("g_use_ammunition"))
\r
912 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
\r
914 warmup_start_health = cvar("g_warmup_start_health");
\r
915 warmup_start_armorvalue = cvar("g_warmup_start_armor");
\r
916 warmup_start_weapons = 0;
\r
917 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
919 e = get_weaponinfo(i);
\r
920 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
\r
922 warmup_start_weapons |= e.weapons;
\r
923 weapon_action(e.weapon, WR_PRECACHE);
\r
930 start_items |= IT_FUEL_REGEN;
\r
931 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
932 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
936 start_items |= IT_JETPACK;
\r
938 if (g_weapon_stay == 2)
\r
940 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
\r
941 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
\r
944 start_ammo_fuel = max(0, start_ammo_fuel);
\r
946 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
\r
950 float g_bugrigs_planar_movement;
\r
951 float g_bugrigs_planar_movement_car_jumping;
\r
952 float g_bugrigs_reverse_spinning;
\r
953 float g_bugrigs_reverse_speeding;
\r
954 float g_bugrigs_reverse_stopping;
\r
955 float g_bugrigs_air_steering;
\r
956 float g_bugrigs_angle_smoothing;
\r
957 float g_bugrigs_friction_floor;
\r
958 float g_bugrigs_friction_brake;
\r
959 float g_bugrigs_friction_air;
\r
960 float g_bugrigs_accel;
\r
961 float g_bugrigs_speed_ref;
\r
962 float g_bugrigs_speed_pow;
\r
963 float g_bugrigs_steer;
\r
965 float g_touchexplode;
\r
966 float g_touchexplode_radius;
\r
967 float g_touchexplode_damage;
\r
968 float g_touchexplode_edgedamage;
\r
969 float g_touchexplode_force;
\r
971 float sv_autotaunt;
\r
974 float sv_pitch_min;
\r
975 float sv_pitch_max;
\r
976 float sv_pitch_fixyaw;
\r
978 float sv_accuracy_data_share;
\r
980 void readlevelcvars(void)
\r
982 g_bugrigs = cvar("g_bugrigs");
\r
983 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
\r
984 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
\r
985 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
\r
986 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
\r
987 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
\r
988 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
\r
989 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
\r
990 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
\r
991 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
\r
992 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
\r
993 g_bugrigs_accel = cvar("g_bugrigs_accel");
\r
994 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
\r
995 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
\r
996 g_bugrigs_steer = cvar("g_bugrigs_steer");
\r
998 g_touchexplode = cvar("g_touchexplode");
\r
999 g_touchexplode_radius = cvar("g_touchexplode_radius");
\r
1000 g_touchexplode_damage = cvar("g_touchexplode_damage");
\r
1001 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
\r
1002 g_touchexplode_force = cvar("g_touchexplode_force");
\r
1004 #ifdef ALLOW_FORCEMODELS
\r
1005 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
\r
1008 sv_clones = cvar("sv_clones");
\r
1009 sv_gentle = cvar("sv_gentle");
\r
1010 sv_foginterval = cvar("sv_foginterval");
\r
1011 g_cloaked = cvar("g_cloaked");
\r
1012 g_jump_grunt = cvar("g_jump_grunt");
\r
1013 g_footsteps = cvar("g_footsteps");
\r
1014 g_jetpack = cvar("g_jetpack");
\r
1015 g_midair = cvar("g_midair");
\r
1016 g_norecoil = cvar("g_norecoil");
\r
1017 g_vampire = cvar("g_vampire");
\r
1018 g_bloodloss = cvar("g_bloodloss");
\r
1019 sv_maxidle = cvar("sv_maxidle");
\r
1020 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
\r
1021 sv_pogostick = cvar("sv_pogostick");
\r
1022 sv_doublejump = cvar("sv_doublejump");
\r
1023 g_ctf_reverse = cvar("g_ctf_reverse");
\r
1024 sv_autotaunt = cvar("sv_autotaunt");
\r
1025 sv_taunt = cvar("sv_taunt");
\r
1027 inWarmupStage = cvar("g_warmup");
\r
1028 g_warmup_limit = cvar("g_warmup_limit");
\r
1029 g_warmup_allguns = cvar("g_warmup_allguns");
\r
1030 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
\r
1032 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
\r
1033 inWarmupStage = 0; // these modes cannot work together, sorry
\r
1035 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
\r
1036 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
\r
1037 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
\r
1038 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
\r
1039 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
\r
1040 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
\r
1041 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
\r
1042 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
\r
1043 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
\r
1044 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
\r
1045 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
\r
1046 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
\r
1048 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
\r
1049 g_weaponratefactor = cvar("g_weaponratefactor");
\r
1050 g_weapondamagefactor = cvar("g_weapondamagefactor");
\r
1051 g_weaponforcefactor = cvar("g_weaponforcefactor");
\r
1052 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
\r
1054 g_pickup_fuel = cvar("g_pickup_fuel");
\r
1055 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
\r
1056 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
\r
1057 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
\r
1058 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
\r
1059 g_pickup_armormedium = cvar("g_pickup_armormedium");
\r
1060 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
\r
1061 g_pickup_armorbig = cvar("g_pickup_armorbig");
\r
1062 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
\r
1063 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
\r
1064 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
\r
1065 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
\r
1066 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
\r
1067 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
\r
1068 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
\r
1069 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
\r
1070 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
\r
1071 g_pickup_healthmega = cvar("g_pickup_healthmega");
\r
1072 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
\r
1074 g_weapon_stay = cvar("g_weapon_stay");
\r
1076 if (!g_weapon_stay && (cvar("deathmatch") == 2))
\r
1077 g_weapon_stay = 1;
\r
1079 g_ghost_items = cvar("g_ghost_items");
\r
1081 if(g_ghost_items >= 1)
\r
1082 g_ghost_items = 0.25; // default alpha value
\r
1084 if not(inWarmupStage && !g_ca)
\r
1085 game_starttime = cvar("g_start_delay");
\r
1087 sv_pitch_min = cvar("sv_pitch_min");
\r
1088 sv_pitch_max = cvar("sv_pitch_max");
\r
1089 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
\r
1091 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
\r
1093 readplayerstartcvars();
\r
1097 // TODO sound pack system
\r
1100 string precache_sound_builtin (string s) = #19;
\r
1101 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1102 string precache_sound(string s)
\r
1104 return precache_sound_builtin(strcat(soundpack, s));
\r
1106 void play2(entity e, string filename)
\r
1108 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
\r
1110 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1112 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
\r
1116 // Sound functions
\r
1117 string precache_sound (string s) = #19;
\r
1118 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1119 float precache_sound_index (string s) = #19;
\r
1121 #define SND_VOLUME 1
\r
1122 #define SND_ATTENUATION 2
\r
1123 #define SND_LARGEENTITY 8
\r
1124 #define SND_LARGESOUND 16
\r
1126 float sound_allowed(float dest, entity e)
\r
1128 // sounds from world may always pass
\r
1131 if (e.classname == "body")
\r
1133 if (e.owner && e.owner != e)
\r
1138 // sounds to self may always pass
\r
1139 if (dest == MSG_ONE)
\r
1140 if (e == msg_entity)
\r
1142 // sounds by players can be removed
\r
1143 if (cvar("bot_sound_monopoly"))
\r
1144 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1146 // anything else may pass
\r
1150 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1152 if (!sound_allowed(MSG_BROADCAST, e))
\r
1154 sound_builtin(e, chan, samp, vol, atten);
\r
1156 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
\r
1160 if (!sound_allowed(dest, e))
\r
1163 entno = num_for_edict(e);
\r
1164 idx = precache_sound_index(samp);
\r
1169 atten = floor(atten * 64);
\r
1170 vol = floor(vol * 255);
\r
1173 sflags |= SND_VOLUME;
\r
1175 sflags |= SND_ATTENUATION;
\r
1176 if (entno >= 8192)
\r
1177 sflags |= SND_LARGEENTITY;
\r
1179 sflags |= SND_LARGESOUND;
\r
1181 WriteByte(dest, SVC_SOUND);
\r
1182 WriteByte(dest, sflags);
\r
1183 if (sflags & SND_VOLUME)
\r
1184 WriteByte(dest, vol);
\r
1185 if (sflags & SND_ATTENUATION)
\r
1186 WriteByte(dest, atten);
\r
1187 if (sflags & SND_LARGEENTITY)
\r
1189 WriteShort(dest, entno);
\r
1190 WriteByte(dest, chan);
\r
1194 WriteShort(dest, entno * 8 + chan);
\r
1196 if (sflags & SND_LARGESOUND)
\r
1197 WriteShort(dest, idx);
\r
1199 WriteByte(dest, idx);
\r
1201 WriteCoord(dest, o_x);
\r
1202 WriteCoord(dest, o_y);
\r
1203 WriteCoord(dest, o_z);
\r
1205 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
\r
1209 if (!sound_allowed(dest, e))
\r
1212 o = e.origin + 0.5 * (e.mins + e.maxs);
\r
1213 soundtoat(dest, e, o, chan, samp, vol, atten);
\r
1215 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
\r
1217 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
\r
1219 void stopsoundto(float dest, entity e, float chan)
\r
1223 if (!sound_allowed(dest, e))
\r
1226 entno = num_for_edict(e);
\r
1228 if (entno >= 8192)
\r
1230 float idx, sflags;
\r
1231 idx = precache_sound_index("misc/null.wav");
\r
1232 sflags = SND_LARGEENTITY;
\r
1234 sflags |= SND_LARGESOUND;
\r
1235 WriteByte(dest, SVC_SOUND);
\r
1236 WriteByte(dest, sflags);
\r
1237 WriteShort(dest, entno);
\r
1238 WriteByte(dest, chan);
\r
1239 if (sflags & SND_LARGESOUND)
\r
1240 WriteShort(dest, idx);
\r
1242 WriteByte(dest, idx);
\r
1243 WriteCoord(dest, e.origin_x);
\r
1244 WriteCoord(dest, e.origin_y);
\r
1245 WriteCoord(dest, e.origin_z);
\r
1249 WriteByte(dest, SVC_STOPSOUND);
\r
1250 WriteShort(dest, entno * 8 + chan);
\r
1253 void stopsound(entity e, float chan)
\r
1255 if (!sound_allowed(MSG_BROADCAST, e))
\r
1258 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
\r
1259 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
\r
1262 void play2(entity e, string filename)
\r
1264 //stuffcmd(e, strcat("play2 ", filename, "\n"));
\r
1266 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
\r
1269 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
\r
1271 float spamsound(entity e, float chan, string samp, float vol, float atten)
\r
1273 if (!sound_allowed(MSG_BROADCAST, e))
\r
1276 if (time > e.spamtime)
\r
1278 e.spamtime = time;
\r
1279 sound(e, chan, samp, vol, atten);
\r
1285 void play2team(float t, string filename)
\r
1287 local entity head;
\r
1289 if (cvar("bot_sound_monopoly"))
\r
1292 FOR_EACH_REALPLAYER(head)
\r
1294 if (head.team == t)
\r
1295 play2(head, filename);
\r
1299 void play2all(string samp)
\r
1301 if (cvar("bot_sound_monopoly"))
\r
1304 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
\r
1307 void PrecachePlayerSounds(string f);
\r
1308 void precache_all_models(string pattern)
\r
1310 float globhandle, i, n;
\r
1313 globhandle = search_begin(pattern, TRUE, FALSE);
\r
1314 if (globhandle < 0)
\r
1316 n = search_getsize(globhandle);
\r
1317 for (i = 0; i < n; ++i)
\r
1319 //print(search_getfilename(globhandle, i), "\n");
\r
1320 f = search_getfilename(globhandle, i);
\r
1321 precache_model(f);
\r
1322 PrecachePlayerSounds(strcat(f, ".sounds"));
\r
1324 search_end(globhandle);
\r
1329 // gamemode related things
\r
1330 precache_model ("models/misc/chatbubble.spr");
\r
1331 precache_model ("models/misc/teambubble.spr");
\r
1332 precache_model ("models/misc/teambubbleheal.spr");
\r
1334 // used by the waypoint editor
\r
1335 precache_model ("models/rune.mdl");
\r
1337 #ifdef TTURRETS_ENABLED
\r
1338 if (cvar("g_turrets"))
\r
1339 turrets_precash();
\r
1342 // Precache all player models if desired
\r
1343 if (cvar("sv_precacheplayermodels"))
\r
1345 PrecachePlayerSounds("sound/player/default.sounds");
\r
1346 precache_all_models("models/player/*.zym");
\r
1347 precache_all_models("models/player/*.dpm");
\r
1348 precache_all_models("models/player/*.md3");
\r
1349 precache_all_models("models/player/*.psk");
\r
1350 //precache_model("models/player/vixen.zym");
\r
1353 if (cvar("sv_defaultcharacter"))
\r
1356 s = cvar_string("sv_defaultplayermodel_red");
\r
1359 precache_model(s);
\r
1360 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1362 s = cvar_string("sv_defaultplayermodel_blue");
\r
1365 precache_model(s);
\r
1366 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1368 s = cvar_string("sv_defaultplayermodel_yellow");
\r
1371 precache_model(s);
\r
1372 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1374 s = cvar_string("sv_defaultplayermodel_pink");
\r
1377 precache_model(s);
\r
1378 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1380 s = cvar_string("sv_defaultplayermodel");
\r
1383 precache_model(s);
\r
1384 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1390 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
\r
1391 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
\r
1394 // gore and miscellaneous sounds
\r
1395 //precache_sound ("misc/h2ohit.wav");
\r
1396 precache_model ("models/grabber.md3");
\r
1397 precache_sound ("misc/armorimpact.wav");
\r
1398 precache_sound ("misc/bodyimpact1.wav");
\r
1399 precache_sound ("misc/bodyimpact2.wav");
\r
1400 precache_sound ("misc/gib.wav");
\r
1401 precache_sound ("misc/gib_splat01.wav");
\r
1402 precache_sound ("misc/gib_splat02.wav");
\r
1403 precache_sound ("misc/gib_splat03.wav");
\r
1404 precache_sound ("misc/gib_splat04.wav");
\r
1405 precache_sound ("misc/hit.wav");
\r
1406 precache_sound ("misc/typehit.wav");
\r
1407 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
\r
1408 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
\r
1409 precache_sound ("misc/null.wav");
\r
1410 precache_sound ("misc/spawn.wav");
\r
1411 precache_sound ("misc/talk.wav");
\r
1412 precache_sound ("misc/teleport.wav");
\r
1413 precache_sound ("misc/poweroff.wav");
\r
1414 precache_sound ("player/lava.wav");
\r
1415 precache_sound ("player/slime.wav");
\r
1416 precache_sound ("player/digest.wav");
\r
1419 precache_sound ("misc/jetpack_fly.wav");
\r
1421 precache_model ("models/sprites/0.spr32");
\r
1422 precache_model ("models/sprites/1.spr32");
\r
1423 precache_model ("models/sprites/2.spr32");
\r
1424 precache_model ("models/sprites/3.spr32");
\r
1425 precache_model ("models/sprites/4.spr32");
\r
1426 precache_model ("models/sprites/5.spr32");
\r
1427 precache_model ("models/sprites/6.spr32");
\r
1428 precache_model ("models/sprites/7.spr32");
\r
1429 precache_model ("models/sprites/8.spr32");
\r
1430 precache_model ("models/sprites/9.spr32");
\r
1431 precache_model ("models/sprites/10.spr32");
\r
1433 // common weapon precaches
\r
1434 precache_sound ("weapons/weapon_switch.wav");
\r
1435 precache_sound ("weapons/weaponpickup.wav");
\r
1436 precache_sound ("weapons/unavailable.wav");
\r
1437 precache_sound ("weapons/grabber_fire.wav"); // grabber
\r
1438 precache_sound ("weapons/grabber_altfire.wav"); // grabber
\r
1439 precache_sound ("weapons/grabber_impact.wav"); // grabber
\r
1440 precache_sound ("weapons/stomachkick.ogg");
\r
1442 if (cvar("sv_precacheweapons"))
\r
1444 //precache weapon models/sounds
\r
1447 while (wep <= WEP_LAST)
\r
1449 weapon_action(wep, WR_PRECACHE);
\r
1454 precache_model("models/elaser.mdl");
\r
1455 precache_model("models/laser.mdl");
\r
1456 precache_model("models/ebomb.mdl");
\r
1459 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
\r
1461 if (!self.noise && self.music) // quake 3 uses the music field
\r
1462 self.noise = self.music;
\r
1464 // plays music for the level if there is any
\r
1467 precache_sound (self.noise);
\r
1468 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
\r
1473 // sorry, but using \ in macros breaks line numbers
\r
1474 #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
\r
1475 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
\r
1476 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
\r
1478 // WARNING: this kills the trace globals
\r
1479 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
\r
1480 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
\r
1482 #define INITPRIO_FIRST 0
\r
1483 #define INITPRIO_GAMETYPE 0
\r
1484 #define INITPRIO_GAMETYPE_FALLBACK 1
\r
1485 #define INITPRIO_CVARS 5
\r
1486 #define INITPRIO_FINDTARGET 10
\r
1487 #define INITPRIO_DROPTOFLOOR 20
\r
1488 #define INITPRIO_SETLOCATION 90
\r
1489 #define INITPRIO_LINKDOORS 91
\r
1490 #define INITPRIO_LAST 99
\r
1492 .void(void) initialize_entity;
\r
1493 .float initialize_entity_order;
\r
1494 .entity initialize_entity_next;
\r
1495 entity initialize_entity_first;
\r
1497 void make_safe_for_remove(entity e)
\r
1499 if (e.initialize_entity)
\r
1502 for (ent = initialize_entity_first; ent; )
\r
1504 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
\r
1506 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
\r
1507 // skip it in linked list
\r
1510 prev.initialize_entity_next = ent.initialize_entity_next;
\r
1511 ent = prev.initialize_entity_next;
\r
1515 initialize_entity_first = ent.initialize_entity_next;
\r
1516 ent = initialize_entity_first;
\r
1522 ent = ent.initialize_entity_next;
\r
1528 void objerror(string s)
\r
1530 make_safe_for_remove(self);
\r
1531 objerror_builtin(s);
\r
1534 void remove_unsafely(entity e)
\r
1536 remove_builtin(e);
\r
1539 void remove_safely(entity e)
\r
1541 make_safe_for_remove(e);
\r
1542 remove_builtin(e);
\r
1545 void InitializeEntity(entity e, void(void) func, float order)
\r
1549 if (!e || e.initialize_entity)
\r
1551 // make a proxy initializer entity
\r
1555 e.classname = "initialize_entity";
\r
1559 e.initialize_entity = func;
\r
1560 e.initialize_entity_order = order;
\r
1562 cur = initialize_entity_first;
\r
1565 if (!cur || cur.initialize_entity_order > order)
\r
1567 // insert between prev and cur
\r
1569 prev.initialize_entity_next = e;
\r
1571 initialize_entity_first = e;
\r
1572 e.initialize_entity_next = cur;
\r
1576 cur = cur.initialize_entity_next;
\r
1579 void InitializeEntitiesRun()
\r
1581 entity startoflist;
\r
1582 startoflist = initialize_entity_first;
\r
1583 initialize_entity_first = world;
\r
1584 for (self = startoflist; self; )
\r
1587 var void(void) func;
\r
1588 e = self.initialize_entity_next;
\r
1589 func = self.initialize_entity;
\r
1590 self.initialize_entity_order = 0;
\r
1591 self.initialize_entity = func_null;
\r
1592 self.initialize_entity_next = world;
\r
1593 if (self.classname == "initialize_entity")
\r
1596 e_old = self.enemy;
\r
1597 remove_builtin(self);
\r
1600 //dprint("Delayed initialization: ", self.classname, "\n");
\r
1606 .float uncustomizeentityforclient_set;
\r
1607 .void(void) uncustomizeentityforclient;
\r
1608 void(void) SUB_Nullpointer = #0;
\r
1609 void UncustomizeEntitiesRun()
\r
1613 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
\r
1614 self.uncustomizeentityforclient();
\r
1617 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
\r
1619 e.customizeentityforclient = customizer;
\r
1620 e.uncustomizeentityforclient = uncustomizer;
\r
1621 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
\r
1624 .float nottargeted;
\r
1625 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
\r
1627 void() SUB_Remove;
\r
1628 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
\r
1632 if (e.classname == "")
\r
1633 e.classname = "net_linked";
\r
1635 if (e.model == "" || self.modelindex == 0)
\r
1639 setmodel(e, "null");
\r
1640 setsize(e, mi, ma);
\r
1643 e.SendEntity = sendfunc;
\r
1644 e.SendFlags = 0xFFFFFF;
\r
1647 e.effects |= EF_NODEPTHTEST;
\r
1651 e.nextthink = time + dt;
\r
1652 e.think = SUB_Remove;
\r
1656 void adaptor_think2touch()
\r
1665 void adaptor_think2use()
\r
1670 activator = world;
\r
1677 // deferred dropping
\r
1678 void DropToFloor_Handler()
\r
1680 droptofloor_builtin();
\r
1681 self.dropped_origin = self.origin;
\r
1684 void droptofloor()
\r
1686 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
\r
1691 float trace_hits_box_a0, trace_hits_box_a1;
\r
1693 float trace_hits_box_1d(float end, float thmi, float thma)
\r
1697 // just check if x is in range
\r
1705 // do the trace with respect to x
\r
1706 // 0 -> end has to stay in thmi -> thma
\r
1707 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
\r
1708 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
\r
1709 if (trace_hits_box_a0 > trace_hits_box_a1)
\r
1715 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
\r
1720 // now it is a trace from 0 to end
\r
1722 trace_hits_box_a0 = 0;
\r
1723 trace_hits_box_a1 = 1;
\r
1725 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
\r
1727 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
\r
1729 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
\r
1735 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
\r
1737 return trace_hits_box(start, end, thmi - ma, thma - mi);
\r
1740 float SUB_NoImpactCheck()
\r
1742 // zero hitcontents = this is not the real impact, but either the
\r
1743 // mirror-impact of something hitting the projectile instead of the
\r
1744 // projectile hitting the something, or a touchareagrid one. Neither of
\r
1745 // these stop the projectile from moving, so...
\r
1746 if(trace_dphitcontents == 0)
\r
1748 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
\r
1751 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1753 if (other == world && self.size != '0 0 0')
\r
1756 tic = self.velocity * sys_frametime;
\r
1757 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
\r
1758 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
\r
1759 if (trace_fraction >= 1)
\r
1761 dprint("Odd... did not hit...?\n");
\r
1763 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1765 dprint("Detected and prevented the sky-grapple bug.\n");
\r
1773 #define SUB_OwnerCheck() (other && (other == self.owner))
\r
1775 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
\r
1777 if(SUB_OwnerCheck())
\r
1779 if(SUB_NoImpactCheck())
\r
1784 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
\r
1785 UpdateCSQCProjectileNextFrame(self);
\r
1788 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
\r
1790 float MAX_IPBAN_URIS = 16;
\r
1792 float URI_GET_DISCARD = 0;
\r
1793 float URI_GET_IPBAN = 1;
\r
1794 float URI_GET_IPBAN_END = 16;
\r
1796 void URI_Get_Callback(float id, float status, string data)
\r
1798 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
\r
1800 dprint("\nEnd of data.\n");
\r
1802 if (id == URI_GET_DISCARD)
\r
1806 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
\r
1808 // online ban list
\r
1809 OnlineBanList_URI_Get_Callback(id, status, data);
\r
1813 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
\r
1817 void print_to(entity e, string s)
\r
1820 sprint(e, strcat(s, "\n"));
\r
1825 string getrecords(float page) // 50 records per page
\r
1839 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1841 if (MapInfo_Get_ByID(i))
\r
1843 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
\r
1846 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
\r
1847 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
\r
1855 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1857 if (MapInfo_Get_ByID(i))
\r
1859 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
\r
1862 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
\r
1863 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1871 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1873 if (MapInfo_Get_ByID(i))
\r
1875 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
\r
1878 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
\r
1879 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1885 MapInfo_ClearTemps();
\r
1887 if (s == "" && page == 0)
\r
1888 return "No records are available on this server.\n";
\r
1893 string getrankings()
\r
1904 map = GetMapname();
\r
1906 for (i = 1; i <= RANKINGS_CNT; ++i)
\r
1908 t = race_GetTime(i);
\r
1911 n = race_GetName(i);
\r
1912 p = race_PlaceName(i);
\r
1913 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
\r
1916 MapInfo_ClearTemps();
\r
1919 return strcat("No records are available for the map: ", map, "\n");
\r
1921 return strcat("Records for ", map, ":\n", s);
\r
1924 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
\r
1927 vector start, org, delta, end, enddown, mstart;
\r
1929 m = e.dphitcontentsmask;
\r
1930 e.dphitcontentsmask = goodcontents | badcontents;
\r
1933 delta = world.maxs - world.mins;
\r
1935 for (i = 0; i < attempts; ++i)
\r
1937 start_x = org_x + random() * delta_x;
\r
1938 start_y = org_y + random() * delta_y;
\r
1939 start_z = org_z + random() * delta_z;
\r
1941 // rule 1: start inside world bounds, and outside
\r
1942 // solid, and don't start from somewhere where you can
\r
1943 // fall down to evil
\r
1944 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1945 if (trace_fraction >= 1)
\r
1947 if (trace_startsolid)
\r
1949 if (trace_dphitcontents & badcontents)
\r
1951 if (trace_dphitq3surfaceflags & badsurfaceflags)
\r
1954 // rule 2: if we are too high, lower the point
\r
1955 if (trace_fraction * delta_z > maxaboveground)
\r
1956 start = trace_endpos + '0 0 1' * maxaboveground;
\r
1957 enddown = trace_endpos;
\r
1959 // rule 3: make sure we aren't outside the map. This only works
\r
1960 // for somewhat well formed maps. A good rule of thumb is that
\r
1961 // the map should have a convex outside hull.
\r
1962 // these can be traceLINES as we already verified the starting box
\r
1963 mstart = start + 0.5 * (e.mins + e.maxs);
\r
1964 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1965 if (trace_fraction >= 1)
\r
1967 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1968 if (trace_fraction >= 1)
\r
1970 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1971 if (trace_fraction >= 1)
\r
1973 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1974 if (trace_fraction >= 1)
\r
1976 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1977 if (trace_fraction >= 1)
\r
1980 // find a random vector to "look at"
\r
1981 end_x = org_x + random() * delta_x;
\r
1982 end_y = org_y + random() * delta_y;
\r
1983 end_z = org_z + random() * delta_z;
\r
1984 end = start + normalize(end - start) * vlen(delta);
\r
1986 // rule 4: start TO end must not be too short
\r
1987 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
\r
1988 if (trace_startsolid)
\r
1990 if (trace_fraction < minviewdistance / vlen(delta))
\r
1993 // rule 5: don't want to look at sky
\r
1994 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
1997 // rule 6: we must not end up in trigger_hurt
\r
1998 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
\r
2000 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
\r
2007 e.dphitcontentsmask = m;
\r
2011 setorigin(e, start);
\r
2012 e.angles = vectoangles(end - start);
\r
2013 dprint("Needed ", ftos(i + 1), " attempts\n");
\r
2020 float zcurveparticles_effectno;
\r
2021 vector zcurveparticles_start;
\r
2022 float zcurveparticles_spd;
\r
2024 void endzcurveparticles()
\r
2026 if(zcurveparticles_effectno)
\r
2029 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
\r
2031 zcurveparticles_effectno = 0;
\r
2034 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
\r
2036 spd = bound(0, floor(spd / 16), 32767);
\r
2037 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
\r
2039 endzcurveparticles();
\r
2040 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
\r
2041 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
\r
2042 WriteShort(MSG_BROADCAST, effectno);
\r
2043 WriteCoord(MSG_BROADCAST, start_x);
\r
2044 WriteCoord(MSG_BROADCAST, start_y);
\r
2045 WriteCoord(MSG_BROADCAST, start_z);
\r
2046 zcurveparticles_effectno = effectno;
\r
2047 zcurveparticles_start = start;
\r
2050 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
\r
2051 WriteCoord(MSG_BROADCAST, end_x);
\r
2052 WriteCoord(MSG_BROADCAST, end_y);
\r
2053 WriteCoord(MSG_BROADCAST, end_z);
\r
2054 WriteCoord(MSG_BROADCAST, end_dz);
\r
2055 zcurveparticles_spd = spd;
\r
2058 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
\r
2061 vector vecxy, velxy;
\r
2063 vecxy = end - start;
\r
2068 if (vlen(velxy) < 0.000001 * fabs(vel_z))
\r
2070 endzcurveparticles();
\r
2071 trailparticles(world, effectno, start, end);
\r
2075 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
\r
2076 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
\r
2079 string GetGametype(); // g_world.qc
\r
2080 void write_recordmarker(entity pl, float tstart, float dt)
\r
2082 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
\r
2084 // also write a marker into demo files for demotc-race-record-extractor to find
\r
2087 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
\r
2088 " ", ftos(tstart), " ", ftos(dt), "\n"));
\r
2091 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
\r
2093 switch(self.owner.cvar_cl_gunalign)
\r
2104 if(allowcenter) // 2: allow center handedness
\r
2117 if(allowcenter) // 2: allow center handedness
\r
2133 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
\r
2138 if (cvar("g_shootfromeye"))
\r
2142 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2150 else if (cvar("g_shootfromcenter"))
\r
2154 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2162 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
\r
2172 else if (cvar("g_shootfromclient"))
\r
2174 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
\r
2181 void attach_sameorigin(entity e, entity to, string tag)
\r
2183 vector org, t_forward, t_left, t_up, e_forward, e_up;
\r
2184 vector org0, ang0;
\r
2190 org = e.origin - gettaginfo(to, gettagindex(to, tag));
\r
2191 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
\r
2192 t_forward = v_forward * tagscale;
\r
2193 t_left = v_right * -tagscale;
\r
2194 t_up = v_up * tagscale;
\r
2196 e.origin_x = org * t_forward;
\r
2197 e.origin_y = org * t_left;
\r
2198 e.origin_z = org * t_up;
\r
2200 // current forward and up directions
\r
2201 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2202 e.angles = AnglesTransform_FromVAngles(e.angles);
\r
2204 e.angles = AnglesTransform_FromAngles(e.angles);
\r
2205 fixedmakevectors(e.angles);
\r
2207 // untransform forward, up!
\r
2208 e_forward_x = v_forward * t_forward;
\r
2209 e_forward_y = v_forward * t_left;
\r
2210 e_forward_z = v_forward * t_up;
\r
2211 e_up_x = v_up * t_forward;
\r
2212 e_up_y = v_up * t_left;
\r
2213 e_up_z = v_up * t_up;
\r
2215 e.angles = fixedvectoangles2(e_forward, e_up);
\r
2216 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2217 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2219 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2221 setattachment(e, to, tag);
\r
2222 setorigin(e, e.origin);
\r
2225 void detach_sameorigin(entity e)
\r
2228 org = gettaginfo(e, 0);
\r
2229 e.angles = fixedvectoangles2(v_forward, v_up);
\r
2230 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2231 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2233 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2234 setorigin(e, org);
\r
2235 setattachment(e, world, "");
\r
2236 setorigin(e, e.origin);
\r
2239 void follow_sameorigin(entity e, entity to)
\r
2241 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
\r
2242 e.aiment = to; // make the hole follow bmodel
\r
2243 e.punchangle = to.angles; // the original angles of bmodel
\r
2244 e.view_ofs = e.origin - to.origin; // relative origin
\r
2245 e.v_angle = e.angles - to.angles; // relative angles
\r
2248 void unfollow_sameorigin(entity e)
\r
2250 e.movetype = MOVETYPE_NONE;
\r
2253 entity gettaginfo_relative_ent;
\r
2254 vector gettaginfo_relative(entity e, float tag)
\r
2256 if (!gettaginfo_relative_ent)
\r
2258 gettaginfo_relative_ent = spawn();
\r
2259 gettaginfo_relative_ent.effects = EF_NODRAW;
\r
2261 gettaginfo_relative_ent.model = e.model;
\r
2262 gettaginfo_relative_ent.modelindex = e.modelindex;
\r
2263 gettaginfo_relative_ent.frame = e.frame;
\r
2264 return gettaginfo(gettaginfo_relative_ent, tag);
\r
2267 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
\r
2271 if (pl.soundentity.cnt & p)
\r
2273 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
\r
2274 pl.soundentity.cnt |= p;
\r
2277 void SoundEntity_StopSound(entity pl, float chan)
\r
2281 if (pl.soundentity.cnt & p)
\r
2283 stopsoundto(MSG_ALL, pl.soundentity, chan);
\r
2284 pl.soundentity.cnt &~= p;
\r
2288 void SoundEntity_Attach(entity pl)
\r
2290 pl.soundentity = spawn();
\r
2291 pl.soundentity.classname = "soundentity";
\r
2292 pl.soundentity.owner = pl;
\r
2293 setattachment(pl.soundentity, pl, "");
\r
2294 setmodel(pl.soundentity, "null");
\r
2297 void SoundEntity_Detach(entity pl)
\r
2300 for (i = 0; i <= 7; ++i)
\r
2301 SoundEntity_StopSound(pl, i);
\r
2305 float ParseCommandPlayerSlotTarget_firsttoken;
\r
2306 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
\r
2314 ParseCommandPlayerSlotTarget_firsttoken = -1;
\r
2318 if (substring(argv(idx), 0, 1) == "#")
\r
2320 s = substring(argv(idx), 1, -1);
\r
2328 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2329 if (s == ftos(stof(s)))
\r
2331 e = edict_num(stof(s));
\r
2332 if (e.flags & FL_CLIENT)
\r
2338 // it must be a nick name
\r
2341 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2344 FOR_EACH_CLIENT(head)
\r
2345 if (head.netname == s)
\r
2353 s = strdecolorize(s);
\r
2355 FOR_EACH_CLIENT(head)
\r
2356 if (strdecolorize(head.netname) == s)
\r
2371 float modeleffect_SendEntity(entity to, float sf)
\r
2374 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
\r
2377 if(self.velocity != '0 0 0')
\r
2379 if(self.angles != '0 0 0')
\r
2381 if(self.avelocity != '0 0 0')
\r
2384 WriteByte(MSG_ENTITY, f);
\r
2385 WriteShort(MSG_ENTITY, self.modelindex);
\r
2386 WriteByte(MSG_ENTITY, self.skin);
\r
2387 WriteByte(MSG_ENTITY, self.frame);
\r
2388 WriteCoord(MSG_ENTITY, self.origin_x);
\r
2389 WriteCoord(MSG_ENTITY, self.origin_y);
\r
2390 WriteCoord(MSG_ENTITY, self.origin_z);
\r
2393 WriteCoord(MSG_ENTITY, self.velocity_x);
\r
2394 WriteCoord(MSG_ENTITY, self.velocity_y);
\r
2395 WriteCoord(MSG_ENTITY, self.velocity_z);
\r
2399 WriteCoord(MSG_ENTITY, self.angles_x);
\r
2400 WriteCoord(MSG_ENTITY, self.angles_y);
\r
2401 WriteCoord(MSG_ENTITY, self.angles_z);
\r
2405 WriteCoord(MSG_ENTITY, self.avelocity_x);
\r
2406 WriteCoord(MSG_ENTITY, self.avelocity_y);
\r
2407 WriteCoord(MSG_ENTITY, self.avelocity_z);
\r
2409 WriteShort(MSG_ENTITY, self.scale * 256.0);
\r
2410 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
\r
2411 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
\r
2412 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
\r
2413 WriteByte(MSG_ENTITY, self.alpha * 255.0);
\r
2418 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)
\r
2423 e.classname = "modeleffect";
\r
2429 e.avelocity = angv;
\r
2431 e.teleport_time = t1;
\r
2435 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2439 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2442 sz = max(e.scale, e.scale2);
\r
2443 setsize(e, e.mins * sz, e.maxs * sz);
\r
2444 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
\r
2447 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
\r
2449 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
\r
2452 float randombit(float bits)
\r
2454 if not(bits & (bits-1)) // this ONLY holds for powers of two!
\r
2463 for(f = 1; f <= bits; f *= 2)
\r
2472 r = (r - 1) / (n - 1);
\r
2479 float randombits(float bits, float k, float error_return)
\r
2483 while(k > 0 && bits != r)
\r
2485 r += randombit(bits - r);
\r
2494 void randombit_test(float bits, float iter)
\r
2498 print(ftos(randombit(bits)), "\n");
\r
2503 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
\r
2505 if(halflifedist > 0)
\r
2506 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
\r
2507 else if(halflifedist < 0)
\r
2508 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
\r
2517 #define cvar_string_normal cvar_string_builtin
\r
2518 #define cvar_normal cvar_builtin
\r
2520 string cvar_string_normal(string n)
\r
2522 if not(cvar_type(n) & 1)
\r
2523 backtrace(strcat("Attempt to access undefined cvar: ", n));
\r
2524 return cvar_string_builtin(n);
\r
2527 float cvar_normal(string n)
\r
2529 return stof(cvar_string_normal(n));
\r
2532 #define cvar_set_normal cvar_set_builtin
\r
2534 void defer_think()
\r
2539 self = self.owner;
\r
2540 oself.think = SUB_Remove;
\r
2541 oself.nextthink = time;
\r
2547 Execute func() after time + fdelay.
\r
2548 self when func is executed = self when defer is called
\r
2550 void defer(float fdelay, void() func)
\r
2557 e.think = defer_think;
\r
2558 e.nextthink = time + fdelay;
\r