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
620 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
\r
621 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
\r
623 #ifdef ALLOW_FORCEMODELS
\r
624 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
\r
625 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromvoretournament, "cl_forceplayermodelsfromvoretournament");
\r
627 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
\r
629 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
\r
632 if (s == "cl_weaponpriority")
\r
633 self.switchweapon = w_getbestweapon(self);
\r
637 float fexists(string f)
\r
640 fh = fopen(f, FILE_READ);
\r
647 void backtrace(string msg)
\r
650 dev = cvar("developer");
\r
651 war = cvar("prvm_backtraceforwarnings");
\r
652 cvar_set("developer", "1");
\r
653 cvar_set("prvm_backtraceforwarnings", "1");
\r
655 print("--- CUT HERE ---\nWARNING: ");
\r
658 remove(world); // isn't there any better way to cause a backtrace?
\r
659 print("\n--- CUT UNTIL HERE ---\n");
\r
660 cvar_set("developer", ftos(dev));
\r
661 cvar_set("prvm_backtraceforwarnings", ftos(war));
\r
664 string Team_ColorCode(float teamid)
\r
666 if (teamid == COLOR_TEAM1)
\r
668 else if (teamid == COLOR_TEAM2)
\r
670 else if (teamid == COLOR_TEAM3)
\r
672 else if (teamid == COLOR_TEAM4)
\r
678 string Team_ColorName(float t)
\r
680 // fixme: Search for team entities and get their .netname's!
\r
681 if (t == COLOR_TEAM1)
\r
683 if (t == COLOR_TEAM2)
\r
685 if (t == COLOR_TEAM3)
\r
687 if (t == COLOR_TEAM4)
\r
692 string Team_ColorNameLowerCase(float t)
\r
694 // fixme: Search for team entities and get their .netname's!
\r
695 if (t == COLOR_TEAM1)
\r
697 if (t == COLOR_TEAM2)
\r
699 if (t == COLOR_TEAM3)
\r
701 if (t == COLOR_TEAM4)
\r
706 float ColourToNumber(string team_colour)
\r
708 if (team_colour == "red")
\r
709 return COLOR_TEAM1;
\r
711 if (team_colour == "blue")
\r
712 return COLOR_TEAM2;
\r
714 if (team_colour == "yellow")
\r
715 return COLOR_TEAM3;
\r
717 if (team_colour == "pink")
\r
718 return COLOR_TEAM4;
\r
720 if (team_colour == "auto")
\r
726 float NumberToTeamNumber(float number)
\r
729 return COLOR_TEAM1;
\r
732 return COLOR_TEAM2;
\r
735 return COLOR_TEAM3;
\r
738 return COLOR_TEAM4;
\r
743 #define CENTERPRIO_POINT 1
\r
744 #define CENTERPRIO_SPAM 2
\r
745 #define CENTERPRIO_VOTE 4
\r
746 #define CENTERPRIO_NORMAL 5
\r
747 #define CENTERPRIO_SHIELDING 7
\r
748 #define CENTERPRIO_MAPVOTE 9
\r
749 #define CENTERPRIO_IDLEKICK 50
\r
750 #define CENTERPRIO_ADMIN 99
\r
751 .float centerprint_priority;
\r
752 .float centerprint_expires;
\r
753 void centerprint_atprio(entity e, float prio, string s)
\r
755 if (intermission_running)
\r
756 if (prio < CENTERPRIO_MAPVOTE)
\r
758 if (time > e.centerprint_expires)
\r
759 e.centerprint_priority = 0;
\r
760 if (prio >= e.centerprint_priority)
\r
762 e.centerprint_priority = prio;
\r
763 if (timeoutStatus == 2)
\r
764 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
\r
766 e.centerprint_expires = time + e.cvar_scr_centertime;
\r
767 centerprint_builtin(e, s);
\r
770 void centerprint_expire(entity e, float prio)
\r
772 if (prio == e.centerprint_priority)
\r
774 e.centerprint_priority = 0;
\r
775 centerprint_builtin(e, "");
\r
778 void centerprint(entity e, string s)
\r
780 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
\r
783 // decolorizes and team colors the player name when needed
\r
784 string playername(entity p)
\r
787 if (teams_matter && !intermission_running && p.classname == "player")
\r
789 t = Team_ColorCode(p.team);
\r
790 return strcat(t, strdecolorize(p.netname));
\r
796 vector randompos(vector m1, vector m2)
\r
800 v_x = m2_x * random() + m1_x;
\r
801 v_y = m2_y * random() + m1_y;
\r
802 v_z = m2_z * random() + m1_z;
\r
806 float g_pickup_fuel;
\r
807 float g_pickup_fuel_jetpack;
\r
808 float g_pickup_fuel_max;
\r
809 float g_pickup_armorsmall;
\r
810 float g_pickup_armorsmall_max;
\r
811 float g_pickup_armormedium;
\r
812 float g_pickup_armormedium_max;
\r
813 float g_pickup_armorbig;
\r
814 float g_pickup_armorbig_max;
\r
815 float g_pickup_armorlarge;
\r
816 float g_pickup_armorlarge_max;
\r
817 float g_pickup_healthsmall;
\r
818 float g_pickup_healthsmall_max;
\r
819 float g_pickup_healthmedium;
\r
820 float g_pickup_healthmedium_max;
\r
821 float g_pickup_healthlarge;
\r
822 float g_pickup_healthlarge_max;
\r
823 float g_pickup_healthmega;
\r
824 float g_pickup_healthmega_max;
\r
825 float g_weaponspeedfactor;
\r
826 float g_weaponratefactor;
\r
827 float g_weapondamagefactor;
\r
828 float g_weaponforcefactor;
\r
829 float g_weaponspreadfactor;
\r
831 float start_weapons;
\r
833 float start_ammo_fuel;
\r
834 float start_health;
\r
835 float start_armorvalue;
\r
836 float warmup_start_weapons;
\r
837 float warmup_start_ammo_fuel;
\r
838 float warmup_start_health;
\r
839 float warmup_start_armorvalue;
\r
840 float g_weapon_stay;
\r
841 float g_ghost_items;
\r
843 entity get_weaponinfo(float w);
\r
845 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
\r
847 var float i = weaponinfo.weapon;
\r
852 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
\r
854 if (t < 0) // "default" weapon selection
\r
855 t = (i == WEP_GRABBER);
\r
860 void readplayerstartcvars()
\r
865 // initialize starting values for players
\r
868 start_health = cvar("g_balance_health_start");
\r
869 start_armorvalue = cvar("g_balance_armor_start");
\r
873 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
\r
874 start_health = cvar("g_lms_start_health");
\r
875 start_armorvalue = cvar("g_lms_start_armor");
\r
877 else if (cvar("g_use_ammunition"))
\r
879 start_ammo_fuel = cvar("g_start_ammo_fuel");
\r
883 start_ammo_fuel = cvar("g_pickup_fuel_max");
\r
884 start_items |= IT_UNLIMITED_AMMO;
\r
887 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
889 e = get_weaponinfo(i);
\r
890 if(want_weapon("g_start_weapon_", e, FALSE))
\r
892 start_weapons |= e.weapons;
\r
893 weapon_action(e.weapon, WR_PRECACHE);
\r
899 warmup_start_ammo_fuel = start_ammo_fuel;
\r
900 warmup_start_health = start_health;
\r
901 warmup_start_armorvalue = start_armorvalue;
\r
902 warmup_start_weapons = start_weapons;
\r
906 if (cvar("g_use_ammunition"))
\r
908 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
\r
910 warmup_start_health = cvar("g_warmup_start_health");
\r
911 warmup_start_armorvalue = cvar("g_warmup_start_armor");
\r
912 warmup_start_weapons = 0;
\r
913 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
915 e = get_weaponinfo(i);
\r
916 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
\r
918 warmup_start_weapons |= e.weapons;
\r
919 weapon_action(e.weapon, WR_PRECACHE);
\r
927 start_items |= IT_FUEL_REGEN;
\r
928 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
929 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
933 start_items |= IT_JETPACK;
\r
935 if (g_weapon_stay == 2)
\r
937 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
\r
938 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
\r
941 start_ammo_fuel = max(0, start_ammo_fuel);
\r
943 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
\r
947 float g_bugrigs_planar_movement;
\r
948 float g_bugrigs_planar_movement_car_jumping;
\r
949 float g_bugrigs_reverse_spinning;
\r
950 float g_bugrigs_reverse_speeding;
\r
951 float g_bugrigs_reverse_stopping;
\r
952 float g_bugrigs_air_steering;
\r
953 float g_bugrigs_angle_smoothing;
\r
954 float g_bugrigs_friction_floor;
\r
955 float g_bugrigs_friction_brake;
\r
956 float g_bugrigs_friction_air;
\r
957 float g_bugrigs_accel;
\r
958 float g_bugrigs_speed_ref;
\r
959 float g_bugrigs_speed_pow;
\r
960 float g_bugrigs_steer;
\r
962 float g_touchexplode;
\r
963 float g_touchexplode_radius;
\r
964 float g_touchexplode_damage;
\r
965 float g_touchexplode_edgedamage;
\r
966 float g_touchexplode_force;
\r
968 float sv_autotaunt;
\r
971 float sv_pitch_min;
\r
972 float sv_pitch_max;
\r
973 float sv_pitch_fixyaw;
\r
975 float sv_accuracy_data_share;
\r
977 void readlevelcvars(void)
\r
979 g_bugrigs = cvar("g_bugrigs");
\r
980 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
\r
981 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
\r
982 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
\r
983 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
\r
984 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
\r
985 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
\r
986 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
\r
987 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
\r
988 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
\r
989 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
\r
990 g_bugrigs_accel = cvar("g_bugrigs_accel");
\r
991 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
\r
992 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
\r
993 g_bugrigs_steer = cvar("g_bugrigs_steer");
\r
995 g_touchexplode = cvar("g_touchexplode");
\r
996 g_touchexplode_radius = cvar("g_touchexplode_radius");
\r
997 g_touchexplode_damage = cvar("g_touchexplode_damage");
\r
998 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
\r
999 g_touchexplode_force = cvar("g_touchexplode_force");
\r
1001 #ifdef ALLOW_FORCEMODELS
\r
1002 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
\r
1005 sv_clones = cvar("sv_clones");
\r
1006 sv_gentle = cvar("sv_gentle");
\r
1007 sv_foginterval = cvar("sv_foginterval");
\r
1008 g_cloaked = cvar("g_cloaked");
\r
1009 g_jump_grunt = cvar("g_jump_grunt");
\r
1010 g_footsteps = cvar("g_footsteps");
\r
1011 g_jetpack = cvar("g_jetpack");
\r
1012 g_midair = cvar("g_midair");
\r
1013 g_norecoil = cvar("g_norecoil");
\r
1014 g_vampire = cvar("g_vampire");
\r
1015 g_bloodloss = cvar("g_bloodloss");
\r
1016 sv_maxidle = cvar("sv_maxidle");
\r
1017 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
\r
1018 sv_pogostick = cvar("sv_pogostick");
\r
1019 sv_doublejump = cvar("sv_doublejump");
\r
1020 g_ctf_reverse = cvar("g_ctf_reverse");
\r
1021 sv_autotaunt = cvar("sv_autotaunt");
\r
1022 sv_taunt = cvar("sv_taunt");
\r
1024 inWarmupStage = cvar("g_warmup");
\r
1025 g_warmup_limit = cvar("g_warmup_limit");
\r
1026 g_warmup_allguns = cvar("g_warmup_allguns");
\r
1027 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
\r
1029 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
\r
1030 inWarmupStage = 0; // these modes cannot work together, sorry
\r
1032 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
\r
1033 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
\r
1034 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
\r
1035 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
\r
1036 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
\r
1037 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
\r
1038 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
\r
1039 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
\r
1040 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
\r
1041 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
\r
1042 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
\r
1043 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
\r
1045 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
\r
1046 g_weaponratefactor = cvar("g_weaponratefactor");
\r
1047 g_weapondamagefactor = cvar("g_weapondamagefactor");
\r
1048 g_weaponforcefactor = cvar("g_weaponforcefactor");
\r
1049 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
\r
1051 g_pickup_fuel = cvar("g_pickup_fuel");
\r
1052 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
\r
1053 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
\r
1054 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
\r
1055 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
\r
1056 g_pickup_armormedium = cvar("g_pickup_armormedium");
\r
1057 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
\r
1058 g_pickup_armorbig = cvar("g_pickup_armorbig");
\r
1059 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
\r
1060 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
\r
1061 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
\r
1062 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
\r
1063 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
\r
1064 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
\r
1065 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
\r
1066 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
\r
1067 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
\r
1068 g_pickup_healthmega = cvar("g_pickup_healthmega");
\r
1069 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
\r
1071 g_weapon_stay = cvar("g_weapon_stay");
\r
1073 if (!g_weapon_stay && (cvar("deathmatch") == 2))
\r
1074 g_weapon_stay = 1;
\r
1076 g_ghost_items = cvar("g_ghost_items");
\r
1078 if(g_ghost_items >= 1)
\r
1079 g_ghost_items = 0.25; // default alpha value
\r
1081 if not(inWarmupStage && !g_ca)
\r
1082 game_starttime = cvar("g_start_delay");
\r
1084 sv_pitch_min = cvar("sv_pitch_min");
\r
1085 sv_pitch_max = cvar("sv_pitch_max");
\r
1086 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
\r
1088 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
\r
1090 readplayerstartcvars();
\r
1094 // TODO sound pack system
\r
1097 string precache_sound_builtin (string s) = #19;
\r
1098 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1099 string precache_sound(string s)
\r
1101 return precache_sound_builtin(strcat(soundpack, s));
\r
1103 void play2(entity e, string filename)
\r
1105 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
\r
1107 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1109 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
\r
1113 // Sound functions
\r
1114 string precache_sound (string s) = #19;
\r
1115 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1116 float precache_sound_index (string s) = #19;
\r
1118 #define SND_VOLUME 1
\r
1119 #define SND_ATTENUATION 2
\r
1120 #define SND_LARGEENTITY 8
\r
1121 #define SND_LARGESOUND 16
\r
1123 float sound_allowed(float dest, entity e)
\r
1125 // sounds from world may always pass
\r
1128 if (e.classname == "body")
\r
1130 if (e.owner && e.owner != e)
\r
1135 // sounds to self may always pass
\r
1136 if (dest == MSG_ONE)
\r
1137 if (e == msg_entity)
\r
1139 // sounds by players can be removed
\r
1140 if (cvar("bot_sound_monopoly"))
\r
1141 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1143 // anything else may pass
\r
1147 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1149 if (!sound_allowed(MSG_BROADCAST, e))
\r
1151 sound_builtin(e, chan, samp, vol, atten);
\r
1153 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
\r
1157 if (!sound_allowed(dest, e))
\r
1160 entno = num_for_edict(e);
\r
1161 idx = precache_sound_index(samp);
\r
1166 atten = floor(atten * 64);
\r
1167 vol = floor(vol * 255);
\r
1170 sflags |= SND_VOLUME;
\r
1172 sflags |= SND_ATTENUATION;
\r
1173 if (entno >= 8192)
\r
1174 sflags |= SND_LARGEENTITY;
\r
1176 sflags |= SND_LARGESOUND;
\r
1178 WriteByte(dest, SVC_SOUND);
\r
1179 WriteByte(dest, sflags);
\r
1180 if (sflags & SND_VOLUME)
\r
1181 WriteByte(dest, vol);
\r
1182 if (sflags & SND_ATTENUATION)
\r
1183 WriteByte(dest, atten);
\r
1184 if (sflags & SND_LARGEENTITY)
\r
1186 WriteShort(dest, entno);
\r
1187 WriteByte(dest, chan);
\r
1191 WriteShort(dest, entno * 8 + chan);
\r
1193 if (sflags & SND_LARGESOUND)
\r
1194 WriteShort(dest, idx);
\r
1196 WriteByte(dest, idx);
\r
1198 WriteCoord(dest, o_x);
\r
1199 WriteCoord(dest, o_y);
\r
1200 WriteCoord(dest, o_z);
\r
1202 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
\r
1206 if (!sound_allowed(dest, e))
\r
1209 o = e.origin + 0.5 * (e.mins + e.maxs);
\r
1210 soundtoat(dest, e, o, chan, samp, vol, atten);
\r
1212 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
\r
1214 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
\r
1216 void stopsoundto(float dest, entity e, float chan)
\r
1220 if (!sound_allowed(dest, e))
\r
1223 entno = num_for_edict(e);
\r
1225 if (entno >= 8192)
\r
1227 float idx, sflags;
\r
1228 idx = precache_sound_index("misc/null.wav");
\r
1229 sflags = SND_LARGEENTITY;
\r
1231 sflags |= SND_LARGESOUND;
\r
1232 WriteByte(dest, SVC_SOUND);
\r
1233 WriteByte(dest, sflags);
\r
1234 WriteShort(dest, entno);
\r
1235 WriteByte(dest, chan);
\r
1236 if (sflags & SND_LARGESOUND)
\r
1237 WriteShort(dest, idx);
\r
1239 WriteByte(dest, idx);
\r
1240 WriteCoord(dest, e.origin_x);
\r
1241 WriteCoord(dest, e.origin_y);
\r
1242 WriteCoord(dest, e.origin_z);
\r
1246 WriteByte(dest, SVC_STOPSOUND);
\r
1247 WriteShort(dest, entno * 8 + chan);
\r
1250 void stopsound(entity e, float chan)
\r
1252 if (!sound_allowed(MSG_BROADCAST, e))
\r
1255 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
\r
1256 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
\r
1259 void play2(entity e, string filename)
\r
1261 //stuffcmd(e, strcat("play2 ", filename, "\n"));
\r
1263 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
\r
1266 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
\r
1268 float spamsound(entity e, float chan, string samp, float vol, float atten)
\r
1270 if (!sound_allowed(MSG_BROADCAST, e))
\r
1273 if (time > e.spamtime)
\r
1275 e.spamtime = time;
\r
1276 sound(e, chan, samp, vol, atten);
\r
1282 void play2team(float t, string filename)
\r
1284 local entity head;
\r
1286 if (cvar("bot_sound_monopoly"))
\r
1289 FOR_EACH_REALPLAYER(head)
\r
1291 if (head.team == t)
\r
1292 play2(head, filename);
\r
1296 void play2all(string samp)
\r
1298 if (cvar("bot_sound_monopoly"))
\r
1301 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
\r
1304 void PrecachePlayerSounds(string f);
\r
1305 void precache_all_models(string pattern)
\r
1307 float globhandle, i, n;
\r
1310 globhandle = search_begin(pattern, TRUE, FALSE);
\r
1311 if (globhandle < 0)
\r
1313 n = search_getsize(globhandle);
\r
1314 for (i = 0; i < n; ++i)
\r
1316 //print(search_getfilename(globhandle, i), "\n");
\r
1317 f = search_getfilename(globhandle, i);
\r
1318 precache_model(f);
\r
1319 PrecachePlayerSounds(strcat(f, ".sounds"));
\r
1321 search_end(globhandle);
\r
1326 // gamemode related things
\r
1327 precache_model ("models/misc/chatbubble.spr");
\r
1328 precache_model ("models/misc/teambubble.spr");
\r
1330 // used by the waypoint editor
\r
1331 precache_model ("models/rune.mdl");
\r
1333 #ifdef TTURRETS_ENABLED
\r
1334 if (cvar("g_turrets"))
\r
1335 turrets_precash();
\r
1338 // Precache all player models if desired
\r
1339 if (cvar("sv_precacheplayermodels"))
\r
1341 PrecachePlayerSounds("sound/player/default.sounds");
\r
1342 precache_all_models("models/player/*.zym");
\r
1343 precache_all_models("models/player/*.dpm");
\r
1344 precache_all_models("models/player/*.md3");
\r
1345 precache_all_models("models/player/*.psk");
\r
1346 //precache_model("models/player/vixen.zym");
\r
1349 if (cvar("sv_defaultcharacter"))
\r
1352 s = cvar_string("sv_defaultplayermodel_red");
\r
1355 precache_model(s);
\r
1356 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1358 s = cvar_string("sv_defaultplayermodel_blue");
\r
1361 precache_model(s);
\r
1362 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1364 s = cvar_string("sv_defaultplayermodel_yellow");
\r
1367 precache_model(s);
\r
1368 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1370 s = cvar_string("sv_defaultplayermodel_pink");
\r
1373 precache_model(s);
\r
1374 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1376 s = cvar_string("sv_defaultplayermodel");
\r
1379 precache_model(s);
\r
1380 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1386 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
\r
1387 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
\r
1390 // gore and miscellaneous sounds
\r
1391 //precache_sound ("misc/h2ohit.wav");
\r
1392 precache_model ("models/grabber.md3");
\r
1393 precache_sound ("misc/armorimpact.wav");
\r
1394 precache_sound ("misc/bodyimpact1.wav");
\r
1395 precache_sound ("misc/bodyimpact2.wav");
\r
1396 precache_sound ("misc/gib.wav");
\r
1397 precache_sound ("misc/gib_splat01.wav");
\r
1398 precache_sound ("misc/gib_splat02.wav");
\r
1399 precache_sound ("misc/gib_splat03.wav");
\r
1400 precache_sound ("misc/gib_splat04.wav");
\r
1401 precache_sound ("misc/hit.wav");
\r
1402 precache_sound ("misc/typehit.wav");
\r
1403 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
\r
1404 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
\r
1405 precache_sound ("misc/null.wav");
\r
1406 precache_sound ("misc/spawn.wav");
\r
1407 precache_sound ("misc/talk.wav");
\r
1408 precache_sound ("misc/teleport.wav");
\r
1409 precache_sound ("misc/poweroff.wav");
\r
1410 precache_sound ("player/lava.wav");
\r
1411 precache_sound ("player/slime.wav");
\r
1412 precache_sound ("player/digest.wav");
\r
1415 precache_sound ("misc/jetpack_fly.wav");
\r
1417 precache_model ("models/sprites/0.spr32");
\r
1418 precache_model ("models/sprites/1.spr32");
\r
1419 precache_model ("models/sprites/2.spr32");
\r
1420 precache_model ("models/sprites/3.spr32");
\r
1421 precache_model ("models/sprites/4.spr32");
\r
1422 precache_model ("models/sprites/5.spr32");
\r
1423 precache_model ("models/sprites/6.spr32");
\r
1424 precache_model ("models/sprites/7.spr32");
\r
1425 precache_model ("models/sprites/8.spr32");
\r
1426 precache_model ("models/sprites/9.spr32");
\r
1427 precache_model ("models/sprites/10.spr32");
\r
1429 // common weapon precaches
\r
1430 precache_sound ("weapons/weapon_switch.wav");
\r
1431 precache_sound ("weapons/weaponpickup.wav");
\r
1432 precache_sound ("weapons/unavailable.wav");
\r
1433 precache_sound ("weapons/grabber_fire.wav"); // grabber
\r
1434 precache_sound ("weapons/grabber_impact.wav"); // grabber
\r
1435 precache_sound ("weapons/stomachkick.ogg");
\r
1437 if (cvar("sv_precacheweapons"))
\r
1439 //precache weapon models/sounds
\r
1442 while (wep <= WEP_LAST)
\r
1444 weapon_action(wep, WR_PRECACHE);
\r
1449 precache_model("models/elaser.mdl");
\r
1450 precache_model("models/laser.mdl");
\r
1451 precache_model("models/ebomb.mdl");
\r
1454 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
\r
1456 if (!self.noise && self.music) // quake 3 uses the music field
\r
1457 self.noise = self.music;
\r
1459 // plays music for the level if there is any
\r
1462 precache_sound (self.noise);
\r
1463 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
\r
1468 // sorry, but using \ in macros breaks line numbers
\r
1469 #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
1470 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
\r
1471 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
\r
1473 // WARNING: this kills the trace globals
\r
1474 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
\r
1475 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
\r
1477 #define INITPRIO_FIRST 0
\r
1478 #define INITPRIO_GAMETYPE 0
\r
1479 #define INITPRIO_GAMETYPE_FALLBACK 1
\r
1480 #define INITPRIO_CVARS 5
\r
1481 #define INITPRIO_FINDTARGET 10
\r
1482 #define INITPRIO_DROPTOFLOOR 20
\r
1483 #define INITPRIO_SETLOCATION 90
\r
1484 #define INITPRIO_LINKDOORS 91
\r
1485 #define INITPRIO_LAST 99
\r
1487 .void(void) initialize_entity;
\r
1488 .float initialize_entity_order;
\r
1489 .entity initialize_entity_next;
\r
1490 entity initialize_entity_first;
\r
1492 void make_safe_for_remove(entity e)
\r
1494 if (e.initialize_entity)
\r
1497 for (ent = initialize_entity_first; ent; )
\r
1499 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
\r
1501 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
\r
1502 // skip it in linked list
\r
1505 prev.initialize_entity_next = ent.initialize_entity_next;
\r
1506 ent = prev.initialize_entity_next;
\r
1510 initialize_entity_first = ent.initialize_entity_next;
\r
1511 ent = initialize_entity_first;
\r
1517 ent = ent.initialize_entity_next;
\r
1523 void objerror(string s)
\r
1525 make_safe_for_remove(self);
\r
1526 objerror_builtin(s);
\r
1529 void remove_unsafely(entity e)
\r
1531 remove_builtin(e);
\r
1534 void remove_safely(entity e)
\r
1536 make_safe_for_remove(e);
\r
1537 remove_builtin(e);
\r
1540 void InitializeEntity(entity e, void(void) func, float order)
\r
1544 if (!e || e.initialize_entity)
\r
1546 // make a proxy initializer entity
\r
1550 e.classname = "initialize_entity";
\r
1554 e.initialize_entity = func;
\r
1555 e.initialize_entity_order = order;
\r
1557 cur = initialize_entity_first;
\r
1560 if (!cur || cur.initialize_entity_order > order)
\r
1562 // insert between prev and cur
\r
1564 prev.initialize_entity_next = e;
\r
1566 initialize_entity_first = e;
\r
1567 e.initialize_entity_next = cur;
\r
1571 cur = cur.initialize_entity_next;
\r
1574 void InitializeEntitiesRun()
\r
1576 entity startoflist;
\r
1577 startoflist = initialize_entity_first;
\r
1578 initialize_entity_first = world;
\r
1579 for (self = startoflist; self; )
\r
1582 var void(void) func;
\r
1583 e = self.initialize_entity_next;
\r
1584 func = self.initialize_entity;
\r
1585 self.initialize_entity_order = 0;
\r
1586 self.initialize_entity = func_null;
\r
1587 self.initialize_entity_next = world;
\r
1588 if (self.classname == "initialize_entity")
\r
1591 e_old = self.enemy;
\r
1592 remove_builtin(self);
\r
1595 //dprint("Delayed initialization: ", self.classname, "\n");
\r
1601 .float uncustomizeentityforclient_set;
\r
1602 .void(void) uncustomizeentityforclient;
\r
1603 void(void) SUB_Nullpointer = #0;
\r
1604 void UncustomizeEntitiesRun()
\r
1608 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
\r
1609 self.uncustomizeentityforclient();
\r
1612 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
\r
1614 e.customizeentityforclient = customizer;
\r
1615 e.uncustomizeentityforclient = uncustomizer;
\r
1616 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
\r
1619 .float nottargeted;
\r
1620 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
\r
1622 void() SUB_Remove;
\r
1623 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
\r
1627 if (e.classname == "")
\r
1628 e.classname = "net_linked";
\r
1630 if (e.model == "" || self.modelindex == 0)
\r
1634 setmodel(e, "null");
\r
1635 setsize(e, mi, ma);
\r
1638 e.SendEntity = sendfunc;
\r
1639 e.SendFlags = 0xFFFFFF;
\r
1642 e.effects |= EF_NODEPTHTEST;
\r
1646 e.nextthink = time + dt;
\r
1647 e.think = SUB_Remove;
\r
1651 void adaptor_think2touch()
\r
1660 void adaptor_think2use()
\r
1665 activator = world;
\r
1672 // deferred dropping
\r
1673 void DropToFloor_Handler()
\r
1675 droptofloor_builtin();
\r
1676 self.dropped_origin = self.origin;
\r
1679 void droptofloor()
\r
1681 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
\r
1686 float trace_hits_box_a0, trace_hits_box_a1;
\r
1688 float trace_hits_box_1d(float end, float thmi, float thma)
\r
1692 // just check if x is in range
\r
1700 // do the trace with respect to x
\r
1701 // 0 -> end has to stay in thmi -> thma
\r
1702 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
\r
1703 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
\r
1704 if (trace_hits_box_a0 > trace_hits_box_a1)
\r
1710 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
\r
1715 // now it is a trace from 0 to end
\r
1717 trace_hits_box_a0 = 0;
\r
1718 trace_hits_box_a1 = 1;
\r
1720 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
\r
1722 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
\r
1724 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
\r
1730 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
\r
1732 return trace_hits_box(start, end, thmi - ma, thma - mi);
\r
1735 float SUB_NoImpactCheck()
\r
1737 // zero hitcontents = this is not the real impact, but either the
\r
1738 // mirror-impact of something hitting the projectile instead of the
\r
1739 // projectile hitting the something, or a touchareagrid one. Neither of
\r
1740 // these stop the projectile from moving, so...
\r
1741 if(trace_dphitcontents == 0)
\r
1743 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
\r
1746 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1748 if (other == world && self.size != '0 0 0')
\r
1751 tic = self.velocity * sys_frametime;
\r
1752 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
\r
1753 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
\r
1754 if (trace_fraction >= 1)
\r
1756 dprint("Odd... did not hit...?\n");
\r
1758 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1760 dprint("Detected and prevented the sky-grapple bug.\n");
\r
1768 #define SUB_OwnerCheck() (other && (other == self.owner))
\r
1770 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
\r
1772 if(SUB_OwnerCheck())
\r
1774 if(SUB_NoImpactCheck())
\r
1779 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
\r
1780 UpdateCSQCProjectileNextFrame(self);
\r
1783 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
\r
1785 float MAX_IPBAN_URIS = 16;
\r
1787 float URI_GET_DISCARD = 0;
\r
1788 float URI_GET_IPBAN = 1;
\r
1789 float URI_GET_IPBAN_END = 16;
\r
1791 void URI_Get_Callback(float id, float status, string data)
\r
1793 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
\r
1795 dprint("\nEnd of data.\n");
\r
1797 if (id == URI_GET_DISCARD)
\r
1801 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
\r
1803 // online ban list
\r
1804 OnlineBanList_URI_Get_Callback(id, status, data);
\r
1808 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
\r
1812 void print_to(entity e, string s)
\r
1815 sprint(e, strcat(s, "\n"));
\r
1820 string getrecords(float page) // 50 records per page
\r
1834 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1836 if (MapInfo_Get_ByID(i))
\r
1838 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
\r
1841 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
\r
1842 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
\r
1850 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1852 if (MapInfo_Get_ByID(i))
\r
1854 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
\r
1857 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
\r
1858 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1866 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1868 if (MapInfo_Get_ByID(i))
\r
1870 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
\r
1873 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
\r
1874 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1880 MapInfo_ClearTemps();
\r
1882 if (s == "" && page == 0)
\r
1883 return "No records are available on this server.\n";
\r
1888 string getrankings()
\r
1899 map = GetMapname();
\r
1901 for (i = 1; i <= RANKINGS_CNT; ++i)
\r
1903 t = race_GetTime(i);
\r
1906 n = race_GetName(i);
\r
1907 p = race_PlaceName(i);
\r
1908 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
\r
1911 MapInfo_ClearTemps();
\r
1914 return strcat("No records are available for the map: ", map, "\n");
\r
1916 return strcat("Records for ", map, ":\n", s);
\r
1919 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
\r
1922 vector start, org, delta, end, enddown, mstart;
\r
1924 m = e.dphitcontentsmask;
\r
1925 e.dphitcontentsmask = goodcontents | badcontents;
\r
1928 delta = world.maxs - world.mins;
\r
1930 for (i = 0; i < attempts; ++i)
\r
1932 start_x = org_x + random() * delta_x;
\r
1933 start_y = org_y + random() * delta_y;
\r
1934 start_z = org_z + random() * delta_z;
\r
1936 // rule 1: start inside world bounds, and outside
\r
1937 // solid, and don't start from somewhere where you can
\r
1938 // fall down to evil
\r
1939 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1940 if (trace_fraction >= 1)
\r
1942 if (trace_startsolid)
\r
1944 if (trace_dphitcontents & badcontents)
\r
1946 if (trace_dphitq3surfaceflags & badsurfaceflags)
\r
1949 // rule 2: if we are too high, lower the point
\r
1950 if (trace_fraction * delta_z > maxaboveground)
\r
1951 start = trace_endpos + '0 0 1' * maxaboveground;
\r
1952 enddown = trace_endpos;
\r
1954 // rule 3: make sure we aren't outside the map. This only works
\r
1955 // for somewhat well formed maps. A good rule of thumb is that
\r
1956 // the map should have a convex outside hull.
\r
1957 // these can be traceLINES as we already verified the starting box
\r
1958 mstart = start + 0.5 * (e.mins + e.maxs);
\r
1959 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1960 if (trace_fraction >= 1)
\r
1962 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1963 if (trace_fraction >= 1)
\r
1965 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1966 if (trace_fraction >= 1)
\r
1968 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1969 if (trace_fraction >= 1)
\r
1971 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1972 if (trace_fraction >= 1)
\r
1975 // find a random vector to "look at"
\r
1976 end_x = org_x + random() * delta_x;
\r
1977 end_y = org_y + random() * delta_y;
\r
1978 end_z = org_z + random() * delta_z;
\r
1979 end = start + normalize(end - start) * vlen(delta);
\r
1981 // rule 4: start TO end must not be too short
\r
1982 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
\r
1983 if (trace_startsolid)
\r
1985 if (trace_fraction < minviewdistance / vlen(delta))
\r
1988 // rule 5: don't want to look at sky
\r
1989 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
1992 // rule 6: we must not end up in trigger_hurt
\r
1993 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
\r
1995 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
\r
2002 e.dphitcontentsmask = m;
\r
2006 setorigin(e, start);
\r
2007 e.angles = vectoangles(end - start);
\r
2008 dprint("Needed ", ftos(i + 1), " attempts\n");
\r
2015 float zcurveparticles_effectno;
\r
2016 vector zcurveparticles_start;
\r
2017 float zcurveparticles_spd;
\r
2019 void endzcurveparticles()
\r
2021 if(zcurveparticles_effectno)
\r
2024 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
\r
2026 zcurveparticles_effectno = 0;
\r
2029 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
\r
2031 spd = bound(0, floor(spd / 16), 32767);
\r
2032 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
\r
2034 endzcurveparticles();
\r
2035 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
\r
2036 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
\r
2037 WriteShort(MSG_BROADCAST, effectno);
\r
2038 WriteCoord(MSG_BROADCAST, start_x);
\r
2039 WriteCoord(MSG_BROADCAST, start_y);
\r
2040 WriteCoord(MSG_BROADCAST, start_z);
\r
2041 zcurveparticles_effectno = effectno;
\r
2042 zcurveparticles_start = start;
\r
2045 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
\r
2046 WriteCoord(MSG_BROADCAST, end_x);
\r
2047 WriteCoord(MSG_BROADCAST, end_y);
\r
2048 WriteCoord(MSG_BROADCAST, end_z);
\r
2049 WriteCoord(MSG_BROADCAST, end_dz);
\r
2050 zcurveparticles_spd = spd;
\r
2053 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
\r
2056 vector vecxy, velxy;
\r
2058 vecxy = end - start;
\r
2063 if (vlen(velxy) < 0.000001 * fabs(vel_z))
\r
2065 endzcurveparticles();
\r
2066 trailparticles(world, effectno, start, end);
\r
2070 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
\r
2071 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
\r
2074 string GetGametype(); // g_world.qc
\r
2075 void write_recordmarker(entity pl, float tstart, float dt)
\r
2077 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
\r
2079 // also write a marker into demo files for demotc-race-record-extractor to find
\r
2082 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
\r
2083 " ", ftos(tstart), " ", ftos(dt), "\n"));
\r
2086 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
\r
2088 switch(self.owner.cvar_cl_gunalign)
\r
2099 if(allowcenter) // 2: allow center handedness
\r
2112 if(allowcenter) // 2: allow center handedness
\r
2128 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
\r
2133 if (cvar("g_shootfromeye"))
\r
2137 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2145 else if (cvar("g_shootfromcenter"))
\r
2149 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2157 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
\r
2167 else if (cvar("g_shootfromclient"))
\r
2169 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
\r
2176 void attach_sameorigin(entity e, entity to, string tag)
\r
2178 vector org, t_forward, t_left, t_up, e_forward, e_up;
\r
2179 vector org0, ang0;
\r
2185 org = e.origin - gettaginfo(to, gettagindex(to, tag));
\r
2186 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
\r
2187 t_forward = v_forward * tagscale;
\r
2188 t_left = v_right * -tagscale;
\r
2189 t_up = v_up * tagscale;
\r
2191 e.origin_x = org * t_forward;
\r
2192 e.origin_y = org * t_left;
\r
2193 e.origin_z = org * t_up;
\r
2195 // current forward and up directions
\r
2196 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2197 e.angles = AnglesTransform_FromVAngles(e.angles);
\r
2199 e.angles = AnglesTransform_FromAngles(e.angles);
\r
2200 fixedmakevectors(e.angles);
\r
2202 // untransform forward, up!
\r
2203 e_forward_x = v_forward * t_forward;
\r
2204 e_forward_y = v_forward * t_left;
\r
2205 e_forward_z = v_forward * t_up;
\r
2206 e_up_x = v_up * t_forward;
\r
2207 e_up_y = v_up * t_left;
\r
2208 e_up_z = v_up * t_up;
\r
2210 e.angles = fixedvectoangles2(e_forward, e_up);
\r
2211 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2212 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2214 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2216 setattachment(e, to, tag);
\r
2217 setorigin(e, e.origin);
\r
2220 void detach_sameorigin(entity e)
\r
2223 org = gettaginfo(e, 0);
\r
2224 e.angles = fixedvectoangles2(v_forward, v_up);
\r
2225 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2226 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2228 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2229 setorigin(e, org);
\r
2230 setattachment(e, world, "");
\r
2231 setorigin(e, e.origin);
\r
2234 void follow_sameorigin(entity e, entity to)
\r
2236 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
\r
2237 e.aiment = to; // make the hole follow bmodel
\r
2238 e.punchangle = to.angles; // the original angles of bmodel
\r
2239 e.view_ofs = e.origin - to.origin; // relative origin
\r
2240 e.v_angle = e.angles - to.angles; // relative angles
\r
2243 void unfollow_sameorigin(entity e)
\r
2245 e.movetype = MOVETYPE_NONE;
\r
2248 entity gettaginfo_relative_ent;
\r
2249 vector gettaginfo_relative(entity e, float tag)
\r
2251 if (!gettaginfo_relative_ent)
\r
2253 gettaginfo_relative_ent = spawn();
\r
2254 gettaginfo_relative_ent.effects = EF_NODRAW;
\r
2256 gettaginfo_relative_ent.model = e.model;
\r
2257 gettaginfo_relative_ent.modelindex = e.modelindex;
\r
2258 gettaginfo_relative_ent.frame = e.frame;
\r
2259 return gettaginfo(gettaginfo_relative_ent, tag);
\r
2262 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
\r
2266 if (pl.soundentity.cnt & p)
\r
2268 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
\r
2269 pl.soundentity.cnt |= p;
\r
2272 void SoundEntity_StopSound(entity pl, float chan)
\r
2276 if (pl.soundentity.cnt & p)
\r
2278 stopsoundto(MSG_ALL, pl.soundentity, chan);
\r
2279 pl.soundentity.cnt &~= p;
\r
2283 void SoundEntity_Attach(entity pl)
\r
2285 pl.soundentity = spawn();
\r
2286 pl.soundentity.classname = "soundentity";
\r
2287 pl.soundentity.owner = pl;
\r
2288 setattachment(pl.soundentity, pl, "");
\r
2289 setmodel(pl.soundentity, "null");
\r
2292 void SoundEntity_Detach(entity pl)
\r
2295 for (i = 0; i <= 7; ++i)
\r
2296 SoundEntity_StopSound(pl, i);
\r
2300 float ParseCommandPlayerSlotTarget_firsttoken;
\r
2301 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
\r
2309 ParseCommandPlayerSlotTarget_firsttoken = -1;
\r
2313 if (substring(argv(idx), 0, 1) == "#")
\r
2315 s = substring(argv(idx), 1, -1);
\r
2323 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2324 if (s == ftos(stof(s)))
\r
2326 e = edict_num(stof(s));
\r
2327 if (e.flags & FL_CLIENT)
\r
2333 // it must be a nick name
\r
2336 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2339 FOR_EACH_CLIENT(head)
\r
2340 if (head.netname == s)
\r
2348 s = strdecolorize(s);
\r
2350 FOR_EACH_CLIENT(head)
\r
2351 if (strdecolorize(head.netname) == s)
\r
2366 float modeleffect_SendEntity(entity to, float sf)
\r
2369 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
\r
2372 if(self.velocity != '0 0 0')
\r
2374 if(self.angles != '0 0 0')
\r
2376 if(self.avelocity != '0 0 0')
\r
2379 WriteByte(MSG_ENTITY, f);
\r
2380 WriteShort(MSG_ENTITY, self.modelindex);
\r
2381 WriteByte(MSG_ENTITY, self.skin);
\r
2382 WriteByte(MSG_ENTITY, self.frame);
\r
2383 WriteCoord(MSG_ENTITY, self.origin_x);
\r
2384 WriteCoord(MSG_ENTITY, self.origin_y);
\r
2385 WriteCoord(MSG_ENTITY, self.origin_z);
\r
2388 WriteCoord(MSG_ENTITY, self.velocity_x);
\r
2389 WriteCoord(MSG_ENTITY, self.velocity_y);
\r
2390 WriteCoord(MSG_ENTITY, self.velocity_z);
\r
2394 WriteCoord(MSG_ENTITY, self.angles_x);
\r
2395 WriteCoord(MSG_ENTITY, self.angles_y);
\r
2396 WriteCoord(MSG_ENTITY, self.angles_z);
\r
2400 WriteCoord(MSG_ENTITY, self.avelocity_x);
\r
2401 WriteCoord(MSG_ENTITY, self.avelocity_y);
\r
2402 WriteCoord(MSG_ENTITY, self.avelocity_z);
\r
2404 WriteShort(MSG_ENTITY, self.scale * 256.0);
\r
2405 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
\r
2406 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
\r
2407 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
\r
2408 WriteByte(MSG_ENTITY, self.alpha * 255.0);
\r
2413 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
2418 e.classname = "modeleffect";
\r
2424 e.avelocity = angv;
\r
2426 e.teleport_time = t1;
\r
2430 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2434 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2437 sz = max(e.scale, e.scale2);
\r
2438 setsize(e, e.mins * sz, e.maxs * sz);
\r
2439 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
\r
2442 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
\r
2444 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
\r
2447 float randombit(float bits)
\r
2449 if not(bits & (bits-1)) // this ONLY holds for powers of two!
\r
2458 for(f = 1; f <= bits; f *= 2)
\r
2467 r = (r - 1) / (n - 1);
\r
2474 float randombits(float bits, float k, float error_return)
\r
2478 while(k > 0 && bits != r)
\r
2480 r += randombit(bits - r);
\r
2489 void randombit_test(float bits, float iter)
\r
2493 print(ftos(randombit(bits)), "\n");
\r
2498 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
\r
2500 if(halflifedist > 0)
\r
2501 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
\r
2502 else if(halflifedist < 0)
\r
2503 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
\r
2512 #define cvar_string_normal cvar_string_builtin
\r
2513 #define cvar_normal cvar_builtin
\r
2515 string cvar_string_normal(string n)
\r
2517 if not(cvar_type(n) & 1)
\r
2518 backtrace(strcat("Attempt to access undefined cvar: ", n));
\r
2519 return cvar_string_builtin(n);
\r
2522 float cvar_normal(string n)
\r
2524 return stof(cvar_string_normal(n));
\r
2527 #define cvar_set_normal cvar_set_builtin
\r
2529 void defer_think()
\r
2534 self = self.owner;
\r
2535 oself.think = SUB_Remove;
\r
2536 oself.nextthink = time;
\r
2542 Execute func() after time + fdelay.
\r
2543 self when func is executed = self when defer is called
\r
2545 void defer(float fdelay, void() func)
\r
2552 e.think = defer_think;
\r
2553 e.nextthink = time + fdelay;
\r