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_swallowmodel, "cl_vore_swallowmodel");
\r
620 GetCvars_handleFloat(s, f, cvar_cl_vore_autodigest, "cl_vore_autodigest");
\r
622 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
\r
623 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
\r
625 #ifdef ALLOW_FORCEMODELS
\r
626 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
\r
627 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromvoretournament, "cl_forceplayermodelsfromvoretournament");
\r
629 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
\r
631 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
\r
634 if (s == "cl_weaponpriority")
\r
635 self.switchweapon = w_getbestweapon(self);
\r
639 float fexists(string f)
\r
642 fh = fopen(f, FILE_READ);
\r
649 void backtrace(string msg)
\r
652 dev = cvar("developer");
\r
653 war = cvar("prvm_backtraceforwarnings");
\r
654 cvar_set("developer", "1");
\r
655 cvar_set("prvm_backtraceforwarnings", "1");
\r
657 print("--- CUT HERE ---\nWARNING: ");
\r
660 remove(world); // isn't there any better way to cause a backtrace?
\r
661 print("\n--- CUT UNTIL HERE ---\n");
\r
662 cvar_set("developer", ftos(dev));
\r
663 cvar_set("prvm_backtraceforwarnings", ftos(war));
\r
666 string Team_ColorCode(float teamid)
\r
668 if (teamid == COLOR_TEAM1)
\r
670 else if (teamid == COLOR_TEAM2)
\r
672 else if (teamid == COLOR_TEAM3)
\r
674 else if (teamid == COLOR_TEAM4)
\r
680 string Team_ColorName(float t)
\r
682 // fixme: Search for team entities and get their .netname's!
\r
683 if (t == COLOR_TEAM1)
\r
685 if (t == COLOR_TEAM2)
\r
687 if (t == COLOR_TEAM3)
\r
689 if (t == COLOR_TEAM4)
\r
694 string Team_ColorNameLowerCase(float t)
\r
696 // fixme: Search for team entities and get their .netname's!
\r
697 if (t == COLOR_TEAM1)
\r
699 if (t == COLOR_TEAM2)
\r
701 if (t == COLOR_TEAM3)
\r
703 if (t == COLOR_TEAM4)
\r
708 float ColourToNumber(string team_colour)
\r
710 if (team_colour == "red")
\r
711 return COLOR_TEAM1;
\r
713 if (team_colour == "blue")
\r
714 return COLOR_TEAM2;
\r
716 if (team_colour == "yellow")
\r
717 return COLOR_TEAM3;
\r
719 if (team_colour == "pink")
\r
720 return COLOR_TEAM4;
\r
722 if (team_colour == "auto")
\r
728 float NumberToTeamNumber(float number)
\r
731 return COLOR_TEAM1;
\r
734 return COLOR_TEAM2;
\r
737 return COLOR_TEAM3;
\r
740 return COLOR_TEAM4;
\r
745 #define CENTERPRIO_POINT 1
\r
746 #define CENTERPRIO_SPAM 2
\r
747 #define CENTERPRIO_VOTE 4
\r
748 #define CENTERPRIO_NORMAL 5
\r
749 #define CENTERPRIO_SHIELDING 7
\r
750 #define CENTERPRIO_MAPVOTE 9
\r
751 #define CENTERPRIO_IDLEKICK 50
\r
752 #define CENTERPRIO_ADMIN 99
\r
753 .float centerprint_priority;
\r
754 .float centerprint_expires;
\r
755 void centerprint_atprio(entity e, float prio, string s)
\r
757 if (intermission_running)
\r
758 if (prio < CENTERPRIO_MAPVOTE)
\r
760 if (time > e.centerprint_expires)
\r
761 e.centerprint_priority = 0;
\r
762 if (prio >= e.centerprint_priority)
\r
764 e.centerprint_priority = prio;
\r
765 if (timeoutStatus == 2)
\r
766 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
\r
768 e.centerprint_expires = time + e.cvar_scr_centertime;
\r
769 centerprint_builtin(e, s);
\r
772 void centerprint_expire(entity e, float prio)
\r
774 if (prio == e.centerprint_priority)
\r
776 e.centerprint_priority = 0;
\r
777 centerprint_builtin(e, "");
\r
780 void centerprint(entity e, string s)
\r
782 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
\r
785 // decolorizes and team colors the player name when needed
\r
786 string playername(entity p)
\r
789 if (teams_matter && !intermission_running && p.classname == "player")
\r
791 t = Team_ColorCode(p.team);
\r
792 return strcat(t, strdecolorize(p.netname));
\r
798 vector randompos(vector m1, vector m2)
\r
802 v_x = m2_x * random() + m1_x;
\r
803 v_y = m2_y * random() + m1_y;
\r
804 v_z = m2_z * random() + m1_z;
\r
808 float g_pickup_fuel;
\r
809 float g_pickup_fuel_jetpack;
\r
810 float g_pickup_fuel_max;
\r
811 float g_pickup_armorsmall;
\r
812 float g_pickup_armorsmall_max;
\r
813 float g_pickup_armormedium;
\r
814 float g_pickup_armormedium_max;
\r
815 float g_pickup_armorbig;
\r
816 float g_pickup_armorbig_max;
\r
817 float g_pickup_armorlarge;
\r
818 float g_pickup_armorlarge_max;
\r
819 float g_pickup_healthsmall;
\r
820 float g_pickup_healthsmall_max;
\r
821 float g_pickup_healthsmall_consumable;
\r
822 float g_pickup_healthmedium;
\r
823 float g_pickup_healthmedium_max;
\r
824 float g_pickup_healthmedium_consumable;
\r
825 float g_pickup_healthlarge;
\r
826 float g_pickup_healthlarge_max;
\r
827 float g_pickup_healthlarge_consumable;
\r
828 float g_pickup_healthmega;
\r
829 float g_pickup_healthmega_max;
\r
830 float g_pickup_healthmega_consumable;
\r
831 float g_weaponspeedfactor;
\r
832 float g_weaponratefactor;
\r
833 float g_weapondamagefactor;
\r
834 float g_weaponforcefactor;
\r
835 float g_weaponspreadfactor;
\r
837 float start_weapons;
\r
839 float start_ammo_fuel;
\r
840 float start_health;
\r
841 float start_armorvalue;
\r
842 float warmup_start_weapons;
\r
843 float warmup_start_ammo_fuel;
\r
844 float warmup_start_health;
\r
845 float warmup_start_armorvalue;
\r
846 float g_weapon_stay;
\r
847 float g_ghost_items;
\r
849 entity get_weaponinfo(float w);
\r
851 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
\r
853 var float i = weaponinfo.weapon;
\r
858 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
\r
860 if (t < 0) // "default" weapon selection
\r
862 if(g_rpg) // no start weapons in RPG by default
\r
865 t = (i == WEP_GRABBER);
\r
871 void readplayerstartcvars()
\r
876 // initialize starting values for players
\r
879 start_health = cvar("g_balance_health_start");
\r
880 start_armorvalue = cvar("g_balance_armor_start");
\r
884 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
\r
885 start_health = cvar("g_lms_start_health");
\r
886 start_armorvalue = cvar("g_lms_start_armor");
\r
888 else if (cvar("g_use_ammunition"))
\r
890 start_ammo_fuel = cvar("g_start_ammo_fuel");
\r
894 start_ammo_fuel = cvar("g_pickup_fuel_max");
\r
895 start_items |= IT_UNLIMITED_AMMO;
\r
898 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
900 e = get_weaponinfo(i);
\r
901 if(want_weapon("g_start_weapon_", e, FALSE))
\r
903 start_weapons |= e.weapons;
\r
904 weapon_action(e.weapon, WR_PRECACHE);
\r
910 warmup_start_ammo_fuel = start_ammo_fuel;
\r
911 warmup_start_health = start_health;
\r
912 warmup_start_armorvalue = start_armorvalue;
\r
913 warmup_start_weapons = start_weapons;
\r
915 if (cvar("g_use_ammunition"))
\r
917 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
\r
919 warmup_start_health = cvar("g_warmup_start_health");
\r
920 warmup_start_armorvalue = cvar("g_warmup_start_armor");
\r
921 warmup_start_weapons = 0;
\r
922 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
924 e = get_weaponinfo(i);
\r
925 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
\r
927 warmup_start_weapons |= e.weapons;
\r
928 weapon_action(e.weapon, WR_PRECACHE);
\r
935 start_items |= IT_FUEL_REGEN;
\r
936 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
937 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
941 start_items |= IT_JETPACK;
\r
943 if (g_weapon_stay == 2)
\r
945 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
\r
946 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
\r
949 start_ammo_fuel = max(0, start_ammo_fuel);
\r
951 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
\r
955 float g_bugrigs_planar_movement;
\r
956 float g_bugrigs_planar_movement_car_jumping;
\r
957 float g_bugrigs_reverse_spinning;
\r
958 float g_bugrigs_reverse_speeding;
\r
959 float g_bugrigs_reverse_stopping;
\r
960 float g_bugrigs_air_steering;
\r
961 float g_bugrigs_angle_smoothing;
\r
962 float g_bugrigs_friction_floor;
\r
963 float g_bugrigs_friction_brake;
\r
964 float g_bugrigs_friction_air;
\r
965 float g_bugrigs_accel;
\r
966 float g_bugrigs_speed_ref;
\r
967 float g_bugrigs_speed_pow;
\r
968 float g_bugrigs_steer;
\r
970 float g_touchexplode;
\r
971 float g_touchexplode_radius;
\r
972 float g_touchexplode_damage;
\r
973 float g_touchexplode_edgedamage;
\r
974 float g_touchexplode_force;
\r
976 float sv_autotaunt;
\r
979 float sv_pitch_min;
\r
980 float sv_pitch_max;
\r
981 float sv_pitch_fixyaw;
\r
983 float sv_accuracy_data_share;
\r
985 void readlevelcvars(void)
\r
987 g_bugrigs = cvar("g_bugrigs");
\r
988 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
\r
989 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
\r
990 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
\r
991 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
\r
992 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
\r
993 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
\r
994 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
\r
995 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
\r
996 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
\r
997 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
\r
998 g_bugrigs_accel = cvar("g_bugrigs_accel");
\r
999 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
\r
1000 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
\r
1001 g_bugrigs_steer = cvar("g_bugrigs_steer");
\r
1003 g_touchexplode = cvar("g_touchexplode");
\r
1004 g_touchexplode_radius = cvar("g_touchexplode_radius");
\r
1005 g_touchexplode_damage = cvar("g_touchexplode_damage");
\r
1006 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
\r
1007 g_touchexplode_force = cvar("g_touchexplode_force");
\r
1009 #ifdef ALLOW_FORCEMODELS
\r
1010 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
\r
1013 sv_clones = cvar("sv_clones");
\r
1014 sv_gentle = cvar("sv_gentle");
\r
1015 sv_foginterval = cvar("sv_foginterval");
\r
1016 g_cloaked = cvar("g_cloaked");
\r
1017 g_jump_grunt = cvar("g_jump_grunt");
\r
1018 g_footsteps = cvar("g_footsteps");
\r
1019 g_jetpack = cvar("g_jetpack");
\r
1020 g_midair = cvar("g_midair");
\r
1021 g_norecoil = cvar("g_norecoil");
\r
1022 g_vampire = cvar("g_vampire");
\r
1023 g_bloodloss = cvar("g_bloodloss");
\r
1024 sv_maxidle = cvar("sv_maxidle");
\r
1025 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
\r
1026 sv_pogostick = cvar("sv_pogostick");
\r
1027 sv_doublejump = cvar("sv_doublejump");
\r
1028 g_ctf_reverse = cvar("g_ctf_reverse");
\r
1029 sv_autotaunt = cvar("sv_autotaunt");
\r
1030 sv_taunt = cvar("sv_taunt");
\r
1032 inWarmupStage = cvar("g_warmup");
\r
1033 g_warmup_limit = cvar("g_warmup_limit");
\r
1034 g_warmup_allguns = cvar("g_warmup_allguns");
\r
1035 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
\r
1037 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || g_rpg || cvar("g_campaign"))
\r
1038 inWarmupStage = 0; // these modes cannot work together, sorry
\r
1040 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
\r
1041 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
\r
1042 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
\r
1043 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
\r
1044 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
\r
1045 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
\r
1046 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
\r
1047 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
\r
1048 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
\r
1049 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
\r
1050 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
\r
1051 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
\r
1053 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
\r
1054 g_weaponratefactor = cvar("g_weaponratefactor");
\r
1055 g_weapondamagefactor = cvar("g_weapondamagefactor");
\r
1056 g_weaponforcefactor = cvar("g_weaponforcefactor");
\r
1057 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
\r
1059 g_pickup_fuel = cvar("g_pickup_fuel");
\r
1060 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
\r
1061 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
\r
1062 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
\r
1063 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
\r
1064 g_pickup_armormedium = cvar("g_pickup_armormedium");
\r
1065 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
\r
1066 g_pickup_armorbig = cvar("g_pickup_armorbig");
\r
1067 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
\r
1068 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
\r
1069 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
\r
1070 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
\r
1071 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
\r
1072 g_pickup_healthsmall_consumable = cvar("g_pickup_healthsmall_consumable");
\r
1073 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
\r
1074 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
\r
1075 g_pickup_healthmedium_consumable = cvar("g_pickup_healthmedium_consumable");
\r
1076 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
\r
1077 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
\r
1078 g_pickup_healthlarge_consumable = cvar("g_pickup_healthlarge_consumable");
\r
1079 g_pickup_healthmega = cvar("g_pickup_healthmega");
\r
1080 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
\r
1081 g_pickup_healthmega_consumable = cvar("g_pickup_healthmega_consumable");
\r
1083 g_weapon_stay = cvar("g_weapon_stay");
\r
1085 if (!g_weapon_stay && (cvar("deathmatch") == 2))
\r
1086 g_weapon_stay = 1;
\r
1088 g_ghost_items = cvar("g_ghost_items");
\r
1090 if(g_ghost_items >= 1)
\r
1091 g_ghost_items = 0.25; // default alpha value
\r
1093 if not(inWarmupStage && !g_ca && !g_rpg)
\r
1094 game_starttime = cvar("g_start_delay");
\r
1096 sv_pitch_min = cvar("sv_pitch_min");
\r
1097 sv_pitch_max = cvar("sv_pitch_max");
\r
1098 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
\r
1100 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
\r
1102 readplayerstartcvars();
\r
1106 // TODO sound pack system
\r
1109 string precache_sound_builtin (string s) = #19;
\r
1110 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1111 string precache_sound(string s)
\r
1113 return precache_sound_builtin(strcat(soundpack, s));
\r
1115 void play2(entity e, string filename)
\r
1117 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
\r
1119 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1121 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
\r
1125 // Sound functions
\r
1126 string precache_sound (string s) = #19;
\r
1127 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1128 float precache_sound_index (string s) = #19;
\r
1130 #define SND_VOLUME 1
\r
1131 #define SND_ATTENUATION 2
\r
1132 #define SND_LARGEENTITY 8
\r
1133 #define SND_LARGESOUND 16
\r
1135 float sound_allowed(float dest, entity e)
\r
1137 // sounds from world may always pass
\r
1140 if (e.classname == "body")
\r
1142 if (e.owner && e.owner != e)
\r
1147 // sounds to self may always pass
\r
1148 if (dest == MSG_ONE)
\r
1149 if (e == msg_entity)
\r
1151 // sounds by players can be removed
\r
1152 if (cvar("bot_sound_monopoly"))
\r
1153 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1155 // anything else may pass
\r
1159 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1161 if (!sound_allowed(MSG_BROADCAST, e))
\r
1163 sound_builtin(e, chan, samp, vol, atten);
\r
1165 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
\r
1169 if (!sound_allowed(dest, e))
\r
1172 entno = num_for_edict(e);
\r
1173 idx = precache_sound_index(samp);
\r
1178 atten = floor(atten * 64);
\r
1179 vol = floor(vol * 255);
\r
1182 sflags |= SND_VOLUME;
\r
1184 sflags |= SND_ATTENUATION;
\r
1185 if (entno >= 8192)
\r
1186 sflags |= SND_LARGEENTITY;
\r
1188 sflags |= SND_LARGESOUND;
\r
1190 WriteByte(dest, SVC_SOUND);
\r
1191 WriteByte(dest, sflags);
\r
1192 if (sflags & SND_VOLUME)
\r
1193 WriteByte(dest, vol);
\r
1194 if (sflags & SND_ATTENUATION)
\r
1195 WriteByte(dest, atten);
\r
1196 if (sflags & SND_LARGEENTITY)
\r
1198 WriteShort(dest, entno);
\r
1199 WriteByte(dest, chan);
\r
1203 WriteShort(dest, entno * 8 + chan);
\r
1205 if (sflags & SND_LARGESOUND)
\r
1206 WriteShort(dest, idx);
\r
1208 WriteByte(dest, idx);
\r
1210 WriteCoord(dest, o_x);
\r
1211 WriteCoord(dest, o_y);
\r
1212 WriteCoord(dest, o_z);
\r
1214 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
\r
1218 if (!sound_allowed(dest, e))
\r
1221 o = e.origin + 0.5 * (e.mins + e.maxs);
\r
1222 soundtoat(dest, e, o, chan, samp, vol, atten);
\r
1224 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
\r
1226 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
\r
1228 void stopsoundto(float dest, entity e, float chan)
\r
1232 if (!sound_allowed(dest, e))
\r
1235 entno = num_for_edict(e);
\r
1237 if (entno >= 8192)
\r
1239 float idx, sflags;
\r
1240 idx = precache_sound_index("misc/null.wav");
\r
1241 sflags = SND_LARGEENTITY;
\r
1243 sflags |= SND_LARGESOUND;
\r
1244 WriteByte(dest, SVC_SOUND);
\r
1245 WriteByte(dest, sflags);
\r
1246 WriteShort(dest, entno);
\r
1247 WriteByte(dest, chan);
\r
1248 if (sflags & SND_LARGESOUND)
\r
1249 WriteShort(dest, idx);
\r
1251 WriteByte(dest, idx);
\r
1252 WriteCoord(dest, e.origin_x);
\r
1253 WriteCoord(dest, e.origin_y);
\r
1254 WriteCoord(dest, e.origin_z);
\r
1258 WriteByte(dest, SVC_STOPSOUND);
\r
1259 WriteShort(dest, entno * 8 + chan);
\r
1262 void stopsound(entity e, float chan)
\r
1264 if (!sound_allowed(MSG_BROADCAST, e))
\r
1267 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
\r
1268 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
\r
1271 void play2(entity e, string filename)
\r
1273 //stuffcmd(e, strcat("play2 ", filename, "\n"));
\r
1274 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1277 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
\r
1281 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
\r
1283 float spamsound(entity e, float chan, string samp, float vol, float atten)
\r
1285 if (!sound_allowed(MSG_BROADCAST, e))
\r
1288 if (time > e.spamtime)
\r
1290 e.spamtime = time;
\r
1291 sound(e, chan, samp, vol, atten);
\r
1297 void play2team(float t, string filename)
\r
1299 local entity head;
\r
1301 if (cvar("bot_sound_monopoly"))
\r
1304 FOR_EACH_REALPLAYER(head)
\r
1306 if (head.team == t)
\r
1307 play2(head, filename);
\r
1311 void play2all(string samp)
\r
1313 if (cvar("bot_sound_monopoly"))
\r
1316 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
\r
1319 void PrecachePlayerSounds(string f);
\r
1320 void precache_all_models(string pattern)
\r
1322 float globhandle, i, n;
\r
1325 globhandle = search_begin(pattern, TRUE, FALSE);
\r
1326 if (globhandle < 0)
\r
1328 n = search_getsize(globhandle);
\r
1329 for (i = 0; i < n; ++i)
\r
1331 //print(search_getfilename(globhandle, i), "\n");
\r
1332 f = search_getfilename(globhandle, i);
\r
1333 precache_model(f);
\r
1334 PrecachePlayerSounds(strcat(f, ".sounds"));
\r
1336 search_end(globhandle);
\r
1341 // gamemode related things
\r
1342 precache_model ("models/misc/chatbubble.spr");
\r
1344 // used by the waypoint editor
\r
1345 precache_model ("models/rune.mdl");
\r
1347 #ifdef TTURRETS_ENABLED
\r
1348 if (cvar("g_turrets"))
\r
1349 turrets_precash();
\r
1352 // Precache all player models if desired
\r
1353 if (cvar("sv_precacheplayermodels"))
\r
1355 PrecachePlayerSounds("sound/player/default.sounds");
\r
1356 precache_all_models("models/player/*.zym");
\r
1357 precache_all_models("models/player/*.dpm");
\r
1358 precache_all_models("models/player/*.md3");
\r
1359 precache_all_models("models/player/*.psk");
\r
1360 precache_all_models("models/player/*.iqm");
\r
1363 if (cvar("sv_defaultcharacter"))
\r
1366 s = cvar_string("sv_defaultplayermodel_red");
\r
1369 precache_model(s);
\r
1370 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1372 s = cvar_string("sv_defaultplayermodel_blue");
\r
1375 precache_model(s);
\r
1376 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1378 s = cvar_string("sv_defaultplayermodel_yellow");
\r
1381 precache_model(s);
\r
1382 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1384 s = cvar_string("sv_defaultplayermodel_pink");
\r
1387 precache_model(s);
\r
1388 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1390 s = cvar_string("sv_defaultplayermodel");
\r
1393 precache_model(s);
\r
1394 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1400 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
\r
1401 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
\r
1404 // gore and miscellaneous sounds
\r
1405 //precache_sound ("misc/h2ohit.wav");
\r
1406 precache_model ("models/grabber.md3");
\r
1407 precache_sound ("misc/armorimpact.wav");
\r
1408 precache_sound ("misc/bodyimpact1.wav");
\r
1409 precache_sound ("misc/bodyimpact2.wav");
\r
1410 precache_sound ("misc/gib.wav");
\r
1411 precache_sound ("misc/gib_splat01.wav");
\r
1412 precache_sound ("misc/gib_splat02.wav");
\r
1413 precache_sound ("misc/gib_splat03.wav");
\r
1414 precache_sound ("misc/gib_splat04.wav");
\r
1415 precache_sound ("misc/hit.wav");
\r
1416 precache_sound ("misc/typehit.wav");
\r
1417 precache_sound ("misc/unavailable.wav");
\r
1418 precache_sound ("misc/forbidden.wav");
\r
1419 precache_sound ("misc/beep.wav");
\r
1420 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
\r
1421 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
\r
1422 precache_sound ("misc/null.wav");
\r
1423 precache_sound ("misc/spawn.wav");
\r
1424 precache_sound ("misc/talk.wav");
\r
1425 precache_sound ("misc/teleport.wav");
\r
1426 precache_sound ("misc/poweroff.wav");
\r
1427 precache_sound ("player/lava.wav");
\r
1428 precache_sound ("player/slime.wav");
\r
1429 precache_sound ("player/digest.wav");
\r
1430 precache_sound ("misc/health_regen.wav");
\r
1431 precache_sound ("misc/armor_regen.wav");
\r
1432 precache_sound ("misc/power_fail.wav");
\r
1435 precache_sound ("misc/jetpack_fly.wav");
\r
1437 precache_model ("models/sprites/0.spr32");
\r
1438 precache_model ("models/sprites/1.spr32");
\r
1439 precache_model ("models/sprites/2.spr32");
\r
1440 precache_model ("models/sprites/3.spr32");
\r
1441 precache_model ("models/sprites/4.spr32");
\r
1442 precache_model ("models/sprites/5.spr32");
\r
1443 precache_model ("models/sprites/6.spr32");
\r
1444 precache_model ("models/sprites/7.spr32");
\r
1445 precache_model ("models/sprites/8.spr32");
\r
1446 precache_model ("models/sprites/9.spr32");
\r
1447 precache_model ("models/sprites/10.spr32");
\r
1449 // common weapon precaches
\r
1450 precache_sound ("weapons/weapon_switch.wav");
\r
1451 precache_sound ("weapons/weaponpickup.wav");
\r
1452 precache_model ("models/weapons/w_displaydigit.md3");
\r
1455 for(i = 0; i < 8; i += 1)
\r
1456 precache_sound (strcat("weapons/hit", ftos(i), ".wav"));
\r
1458 if (cvar("sv_precacheweapons"))
\r
1460 //precache weapon models/sounds
\r
1463 while (wep <= WEP_LAST)
\r
1465 weapon_action(wep, WR_PRECACHE);
\r
1470 precache_model("models/elaser.mdl");
\r
1471 precache_model("models/laser.mdl");
\r
1472 precache_model("models/ebomb.mdl");
\r
1475 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
\r
1477 if (!self.noise && self.music) // quake 3 uses the music field
\r
1478 self.noise = self.music;
\r
1480 // plays music for the level if there is any
\r
1483 precache_sound (self.noise);
\r
1484 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
\r
1489 // sorry, but using \ in macros breaks line numbers
\r
1490 #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
1491 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
\r
1492 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
\r
1494 // WARNING: this kills the trace globals
\r
1495 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
\r
1496 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
\r
1498 #define INITPRIO_FIRST 0
\r
1499 #define INITPRIO_GAMETYPE 0
\r
1500 #define INITPRIO_GAMETYPE_FALLBACK 1
\r
1501 #define INITPRIO_CVARS 5
\r
1502 #define INITPRIO_FINDTARGET 10
\r
1503 #define INITPRIO_DROPTOFLOOR 20
\r
1504 #define INITPRIO_SETLOCATION 90
\r
1505 #define INITPRIO_LINKDOORS 91
\r
1506 #define INITPRIO_LAST 99
\r
1508 .void(void) initialize_entity;
\r
1509 .float initialize_entity_order;
\r
1510 .entity initialize_entity_next;
\r
1511 entity initialize_entity_first;
\r
1513 void make_safe_for_remove(entity e)
\r
1515 if (e.initialize_entity)
\r
1518 for (ent = initialize_entity_first; ent; )
\r
1520 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
\r
1522 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
\r
1523 // skip it in linked list
\r
1526 prev.initialize_entity_next = ent.initialize_entity_next;
\r
1527 ent = prev.initialize_entity_next;
\r
1531 initialize_entity_first = ent.initialize_entity_next;
\r
1532 ent = initialize_entity_first;
\r
1538 ent = ent.initialize_entity_next;
\r
1544 void objerror(string s)
\r
1546 make_safe_for_remove(self);
\r
1547 objerror_builtin(s);
\r
1550 void remove_unsafely(entity e)
\r
1552 remove_builtin(e);
\r
1555 void remove_safely(entity e)
\r
1557 make_safe_for_remove(e);
\r
1558 remove_builtin(e);
\r
1561 void InitializeEntity(entity e, void(void) func, float order)
\r
1565 if (!e || e.initialize_entity)
\r
1567 // make a proxy initializer entity
\r
1571 e.classname = "initialize_entity";
\r
1575 e.initialize_entity = func;
\r
1576 e.initialize_entity_order = order;
\r
1578 cur = initialize_entity_first;
\r
1581 if (!cur || cur.initialize_entity_order > order)
\r
1583 // insert between prev and cur
\r
1585 prev.initialize_entity_next = e;
\r
1587 initialize_entity_first = e;
\r
1588 e.initialize_entity_next = cur;
\r
1592 cur = cur.initialize_entity_next;
\r
1595 void InitializeEntitiesRun()
\r
1597 entity startoflist;
\r
1598 startoflist = initialize_entity_first;
\r
1599 initialize_entity_first = world;
\r
1600 for (self = startoflist; self; )
\r
1603 var void(void) func;
\r
1604 e = self.initialize_entity_next;
\r
1605 func = self.initialize_entity;
\r
1606 self.initialize_entity_order = 0;
\r
1607 self.initialize_entity = func_null;
\r
1608 self.initialize_entity_next = world;
\r
1609 if (self.classname == "initialize_entity")
\r
1612 e_old = self.enemy;
\r
1613 remove_builtin(self);
\r
1616 //dprint("Delayed initialization: ", self.classname, "\n");
\r
1622 .float uncustomizeentityforclient_set;
\r
1623 .void(void) uncustomizeentityforclient;
\r
1624 void(void) SUB_Nullpointer = #0;
\r
1625 void UncustomizeEntitiesRun()
\r
1629 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
\r
1630 self.uncustomizeentityforclient();
\r
1633 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
\r
1635 e.customizeentityforclient = customizer;
\r
1636 e.uncustomizeentityforclient = uncustomizer;
\r
1637 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
\r
1640 .float nottargeted;
\r
1641 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
\r
1643 void() SUB_Remove;
\r
1644 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
\r
1648 if (e.classname == "")
\r
1649 e.classname = "net_linked";
\r
1651 if (e.model == "" || self.modelindex == 0)
\r
1655 setmodel(e, "null");
\r
1656 setsize(e, mi, ma);
\r
1659 e.SendEntity = sendfunc;
\r
1660 e.SendFlags = 0xFFFFFF;
\r
1663 e.effects |= EF_NODEPTHTEST;
\r
1667 e.nextthink = time + dt;
\r
1668 e.think = SUB_Remove;
\r
1672 void adaptor_think2touch()
\r
1681 void adaptor_think2use()
\r
1686 activator = world;
\r
1693 // deferred dropping
\r
1694 void DropToFloor_Handler()
\r
1696 droptofloor_builtin();
\r
1697 self.dropped_origin = self.origin;
\r
1700 void droptofloor()
\r
1702 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
\r
1707 float trace_hits_box_a0, trace_hits_box_a1;
\r
1709 float trace_hits_box_1d(float end, float thmi, float thma)
\r
1713 // just check if x is in range
\r
1721 // do the trace with respect to x
\r
1722 // 0 -> end has to stay in thmi -> thma
\r
1723 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
\r
1724 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
\r
1725 if (trace_hits_box_a0 > trace_hits_box_a1)
\r
1731 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
\r
1736 // now it is a trace from 0 to end
\r
1738 trace_hits_box_a0 = 0;
\r
1739 trace_hits_box_a1 = 1;
\r
1741 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
\r
1743 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
\r
1745 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
\r
1751 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
\r
1753 return trace_hits_box(start, end, thmi - ma, thma - mi);
\r
1756 float SUB_NoImpactCheck()
\r
1758 // zero hitcontents = this is not the real impact, but either the
\r
1759 // mirror-impact of something hitting the projectile instead of the
\r
1760 // projectile hitting the something, or a touchareagrid one. Neither of
\r
1761 // these stop the projectile from moving, so...
\r
1762 if(trace_dphitcontents == 0)
\r
1764 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
\r
1767 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1769 if (other == world && self.size != '0 0 0')
\r
1772 tic = self.velocity * sys_frametime;
\r
1773 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
\r
1774 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
\r
1775 if (trace_fraction >= 1)
\r
1777 dprint("Odd... did not hit...?\n");
\r
1779 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1781 dprint("Detected and prevented the sky-grapple bug.\n");
\r
1789 #define SUB_OwnerCheck() (other && (other == self.owner))
\r
1791 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
\r
1793 if(SUB_OwnerCheck())
\r
1795 if(SUB_NoImpactCheck())
\r
1800 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
\r
1801 UpdateCSQCProjectileNextFrame(self);
\r
1804 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
\r
1806 float MAX_IPBAN_URIS = 16;
\r
1808 float URI_GET_DISCARD = 0;
\r
1809 float URI_GET_IPBAN = 1;
\r
1810 float URI_GET_IPBAN_END = 16;
\r
1812 void URI_Get_Callback(float id, float status, string data)
\r
1814 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
\r
1816 dprint("\nEnd of data.\n");
\r
1818 if (id == URI_GET_DISCARD)
\r
1822 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
\r
1824 // online ban list
\r
1825 OnlineBanList_URI_Get_Callback(id, status, data);
\r
1829 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
\r
1833 void print_to(entity e, string s)
\r
1836 sprint(e, strcat(s, "\n"));
\r
1841 string getrecords(float page) // 50 records per page
\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, "/captimerecord/time")));
\r
1862 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
\r
1863 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", 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, RACE_RECORD, "time")));
\r
1878 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
\r
1879 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1887 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1889 if (MapInfo_Get_ByID(i))
\r
1891 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
\r
1894 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
\r
1895 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1901 MapInfo_ClearTemps();
\r
1903 if (s == "" && page == 0)
\r
1904 return "No records are available on this server.\n";
\r
1909 string getrankings()
\r
1920 map = GetMapname();
\r
1922 for (i = 1; i <= RANKINGS_CNT; ++i)
\r
1924 t = race_GetTime(i);
\r
1927 n = race_GetName(i);
\r
1928 p = race_PlaceName(i);
\r
1929 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
\r
1932 MapInfo_ClearTemps();
\r
1935 return strcat("No records are available for the map: ", map, "\n");
\r
1937 return strcat("Records for ", map, ":\n", s);
\r
1940 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
\r
1943 vector start, org, delta, end, enddown, mstart;
\r
1945 m = e.dphitcontentsmask;
\r
1946 e.dphitcontentsmask = goodcontents | badcontents;
\r
1949 delta = world.maxs - world.mins;
\r
1951 for (i = 0; i < attempts; ++i)
\r
1953 start_x = org_x + random() * delta_x;
\r
1954 start_y = org_y + random() * delta_y;
\r
1955 start_z = org_z + random() * delta_z;
\r
1957 // rule 1: start inside world bounds, and outside
\r
1958 // solid, and don't start from somewhere where you can
\r
1959 // fall down to evil
\r
1960 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1961 if (trace_fraction >= 1)
\r
1963 if (trace_startsolid)
\r
1965 if (trace_dphitcontents & badcontents)
\r
1967 if (trace_dphitq3surfaceflags & badsurfaceflags)
\r
1970 // rule 2: if we are too high, lower the point
\r
1971 if (trace_fraction * delta_z > maxaboveground)
\r
1972 start = trace_endpos + '0 0 1' * maxaboveground;
\r
1973 enddown = trace_endpos;
\r
1975 // rule 3: make sure we aren't outside the map. This only works
\r
1976 // for somewhat well formed maps. A good rule of thumb is that
\r
1977 // the map should have a convex outside hull.
\r
1978 // these can be traceLINES as we already verified the starting box
\r
1979 mstart = start + 0.5 * (e.mins + e.maxs);
\r
1980 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1981 if (trace_fraction >= 1)
\r
1983 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1984 if (trace_fraction >= 1)
\r
1986 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1987 if (trace_fraction >= 1)
\r
1989 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1990 if (trace_fraction >= 1)
\r
1992 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1993 if (trace_fraction >= 1)
\r
1996 // find a random vector to "look at"
\r
1997 end_x = org_x + random() * delta_x;
\r
1998 end_y = org_y + random() * delta_y;
\r
1999 end_z = org_z + random() * delta_z;
\r
2000 end = start + normalize(end - start) * vlen(delta);
\r
2002 // rule 4: start TO end must not be too short
\r
2003 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
\r
2004 if (trace_startsolid)
\r
2006 if (trace_fraction < minviewdistance / vlen(delta))
\r
2009 // rule 5: don't want to look at sky
\r
2010 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
2013 // rule 6: we must not end up in trigger_hurt
\r
2014 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
\r
2016 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
\r
2023 e.dphitcontentsmask = m;
\r
2027 setorigin(e, start);
\r
2028 e.angles = vectoangles(end - start);
\r
2029 dprint("Needed ", ftos(i + 1), " attempts\n");
\r
2036 float zcurveparticles_effectno;
\r
2037 vector zcurveparticles_start;
\r
2038 float zcurveparticles_spd;
\r
2040 void endzcurveparticles()
\r
2042 if(zcurveparticles_effectno)
\r
2045 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
\r
2047 zcurveparticles_effectno = 0;
\r
2050 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
\r
2052 spd = bound(0, floor(spd / 16), 32767);
\r
2053 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
\r
2055 endzcurveparticles();
\r
2056 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
\r
2057 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
\r
2058 WriteShort(MSG_BROADCAST, effectno);
\r
2059 WriteCoord(MSG_BROADCAST, start_x);
\r
2060 WriteCoord(MSG_BROADCAST, start_y);
\r
2061 WriteCoord(MSG_BROADCAST, start_z);
\r
2062 zcurveparticles_effectno = effectno;
\r
2063 zcurveparticles_start = start;
\r
2066 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
\r
2067 WriteCoord(MSG_BROADCAST, end_x);
\r
2068 WriteCoord(MSG_BROADCAST, end_y);
\r
2069 WriteCoord(MSG_BROADCAST, end_z);
\r
2070 WriteCoord(MSG_BROADCAST, end_dz);
\r
2071 zcurveparticles_spd = spd;
\r
2074 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
\r
2077 vector vecxy, velxy;
\r
2079 vecxy = end - start;
\r
2084 if (vlen(velxy) < 0.000001 * fabs(vel_z))
\r
2086 endzcurveparticles();
\r
2087 trailparticles(world, effectno, start, end);
\r
2091 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
\r
2092 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
\r
2095 string GetGametype(); // g_world.qc
\r
2096 void write_recordmarker(entity pl, float tstart, float dt)
\r
2098 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
\r
2100 // also write a marker into demo files for demotc-race-record-extractor to find
\r
2103 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
\r
2104 " ", ftos(tstart), " ", ftos(dt), "\n"));
\r
2107 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
\r
2109 switch(self.owner.cvar_cl_gunalign)
\r
2120 if(allowcenter) // 2: allow center handedness
\r
2133 if(allowcenter) // 2: allow center handedness
\r
2149 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
\r
2154 if (cvar("g_shootfromeye"))
\r
2158 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2166 else if (cvar("g_shootfromcenter"))
\r
2170 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2178 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
\r
2188 else if (cvar("g_shootfromclient"))
\r
2190 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
\r
2197 void attach_sameorigin(entity e, entity to, string tag)
\r
2199 vector org, t_forward, t_left, t_up, e_forward, e_up;
\r
2200 vector org0, ang0;
\r
2206 org = e.origin - gettaginfo(to, gettagindex(to, tag));
\r
2207 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
\r
2208 t_forward = v_forward * tagscale;
\r
2209 t_left = v_right * -tagscale;
\r
2210 t_up = v_up * tagscale;
\r
2212 e.origin_x = org * t_forward;
\r
2213 e.origin_y = org * t_left;
\r
2214 e.origin_z = org * t_up;
\r
2216 // current forward and up directions
\r
2217 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2218 e.angles = AnglesTransform_FromVAngles(e.angles);
\r
2220 e.angles = AnglesTransform_FromAngles(e.angles);
\r
2221 fixedmakevectors(e.angles);
\r
2223 // untransform forward, up!
\r
2224 e_forward_x = v_forward * t_forward;
\r
2225 e_forward_y = v_forward * t_left;
\r
2226 e_forward_z = v_forward * t_up;
\r
2227 e_up_x = v_up * t_forward;
\r
2228 e_up_y = v_up * t_left;
\r
2229 e_up_z = v_up * t_up;
\r
2231 e.angles = fixedvectoangles2(e_forward, e_up);
\r
2232 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2233 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2235 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2237 setattachment(e, to, tag);
\r
2238 setorigin(e, e.origin);
\r
2241 void detach_sameorigin(entity e)
\r
2244 org = gettaginfo(e, 0);
\r
2245 e.angles = fixedvectoangles2(v_forward, v_up);
\r
2246 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2247 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2249 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2250 setorigin(e, org);
\r
2251 setattachment(e, world, "");
\r
2252 setorigin(e, e.origin);
\r
2255 void follow_sameorigin(entity e, entity to)
\r
2257 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
\r
2258 e.aiment = to; // make the hole follow bmodel
\r
2259 e.punchangle = to.angles; // the original angles of bmodel
\r
2260 e.view_ofs = e.origin - to.origin; // relative origin
\r
2261 e.v_angle = e.angles - to.angles; // relative angles
\r
2264 void unfollow_sameorigin(entity e)
\r
2266 e.movetype = MOVETYPE_NONE;
\r
2269 entity gettaginfo_relative_ent;
\r
2270 vector gettaginfo_relative(entity e, float tag)
\r
2272 if (!gettaginfo_relative_ent)
\r
2274 gettaginfo_relative_ent = spawn();
\r
2275 gettaginfo_relative_ent.effects = EF_NODRAW;
\r
2277 gettaginfo_relative_ent.model = e.model;
\r
2278 gettaginfo_relative_ent.modelindex = e.modelindex;
\r
2279 gettaginfo_relative_ent.frame = e.frame;
\r
2280 return gettaginfo(gettaginfo_relative_ent, tag);
\r
2283 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
\r
2287 if (pl.soundentity.cnt & p)
\r
2289 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
\r
2290 pl.soundentity.cnt |= p;
\r
2293 void SoundEntity_StopSound(entity pl, float chan)
\r
2297 if (pl.soundentity.cnt & p)
\r
2299 stopsoundto(MSG_ALL, pl.soundentity, chan);
\r
2300 pl.soundentity.cnt &~= p;
\r
2304 void SoundEntity_Attach(entity pl)
\r
2306 pl.soundentity = spawn();
\r
2307 pl.soundentity.classname = "soundentity";
\r
2308 pl.soundentity.owner = pl;
\r
2309 setattachment(pl.soundentity, pl, "");
\r
2310 setmodel(pl.soundentity, "null");
\r
2313 void SoundEntity_Detach(entity pl)
\r
2316 for (i = 0; i <= 7; ++i)
\r
2317 SoundEntity_StopSound(pl, i);
\r
2321 float ParseCommandPlayerSlotTarget_firsttoken;
\r
2322 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
\r
2330 ParseCommandPlayerSlotTarget_firsttoken = -1;
\r
2334 if (substring(argv(idx), 0, 1) == "#")
\r
2336 s = substring(argv(idx), 1, -1);
\r
2344 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2345 if (s == ftos(stof(s)))
\r
2347 e = edict_num(stof(s));
\r
2348 if (e.flags & FL_CLIENT)
\r
2354 // it must be a nick name
\r
2357 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2360 FOR_EACH_CLIENT(head)
\r
2361 if (head.netname == s)
\r
2369 s = strdecolorize(s);
\r
2371 FOR_EACH_CLIENT(head)
\r
2372 if (strdecolorize(head.netname) == s)
\r
2387 float modeleffect_SendEntity(entity to, float sf)
\r
2390 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
\r
2393 if(self.velocity != '0 0 0')
\r
2395 if(self.angles != '0 0 0')
\r
2397 if(self.avelocity != '0 0 0')
\r
2400 WriteByte(MSG_ENTITY, f);
\r
2401 WriteShort(MSG_ENTITY, self.modelindex);
\r
2402 WriteByte(MSG_ENTITY, self.skin);
\r
2403 WriteByte(MSG_ENTITY, self.frame);
\r
2404 WriteCoord(MSG_ENTITY, self.origin_x);
\r
2405 WriteCoord(MSG_ENTITY, self.origin_y);
\r
2406 WriteCoord(MSG_ENTITY, self.origin_z);
\r
2409 WriteCoord(MSG_ENTITY, self.velocity_x);
\r
2410 WriteCoord(MSG_ENTITY, self.velocity_y);
\r
2411 WriteCoord(MSG_ENTITY, self.velocity_z);
\r
2415 WriteCoord(MSG_ENTITY, self.angles_x);
\r
2416 WriteCoord(MSG_ENTITY, self.angles_y);
\r
2417 WriteCoord(MSG_ENTITY, self.angles_z);
\r
2421 WriteCoord(MSG_ENTITY, self.avelocity_x);
\r
2422 WriteCoord(MSG_ENTITY, self.avelocity_y);
\r
2423 WriteCoord(MSG_ENTITY, self.avelocity_z);
\r
2425 WriteShort(MSG_ENTITY, self.scale * 256.0);
\r
2426 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
\r
2427 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
\r
2428 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
\r
2429 WriteByte(MSG_ENTITY, self.alpha * 255.0);
\r
2434 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
2439 e.classname = "modeleffect";
\r
2445 e.avelocity = angv;
\r
2447 e.teleport_time = t1;
\r
2451 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2455 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2458 sz = max(e.scale, e.scale2);
\r
2459 setsize(e, e.mins * sz, e.maxs * sz);
\r
2460 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
\r
2463 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
\r
2465 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
\r
2468 float randombit(float bits)
\r
2470 if not(bits & (bits-1)) // this ONLY holds for powers of two!
\r
2479 for(f = 1; f <= bits; f *= 2)
\r
2488 r = (r - 1) / (n - 1);
\r
2495 float randombits(float bits, float k, float error_return)
\r
2499 while(k > 0 && bits != r)
\r
2501 r += randombit(bits - r);
\r
2510 void randombit_test(float bits, float iter)
\r
2514 print(ftos(randombit(bits)), "\n");
\r
2519 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
\r
2521 if(halflifedist > 0)
\r
2522 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
\r
2523 else if(halflifedist < 0)
\r
2524 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
\r
2533 #define cvar_string_normal cvar_string_builtin
\r
2534 #define cvar_normal cvar_builtin
\r
2536 string cvar_string_normal(string n)
\r
2538 if not(cvar_type(n) & 1)
\r
2539 backtrace(strcat("Attempt to access undefined cvar: ", n));
\r
2540 return cvar_string_builtin(n);
\r
2543 float cvar_normal(string n)
\r
2545 return stof(cvar_string_normal(n));
\r
2548 #define cvar_set_normal cvar_set_builtin
\r
2550 void defer_think()
\r
2555 self = self.owner;
\r
2556 oself.think = SUB_Remove;
\r
2557 oself.nextthink = time;
\r
2563 Execute func() after time + fdelay.
\r
2564 self when func is executed = self when defer is called
\r
2566 void defer(float fdelay, void() func)
\r
2573 e.think = defer_think;
\r
2574 e.nextthink = time + fdelay;
\r