1 var void remove(entity e);
\r
2 void objerror(string s);
\r
4 .vector dropped_origin;
\r
6 void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
\r
7 void crosshair_trace(entity pl)
\r
9 traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
\r
11 void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
\r
12 void WarpZone_crosshair_trace(entity pl)
\r
14 WarpZone_traceline_antilag(pl, pl.cursor_trace_start, pl.cursor_trace_start + normalize(pl.cursor_trace_endpos - pl.cursor_trace_start) * MAX_SHOT_DISTANCE, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
\r
17 void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
\r
18 void() spawnpoint_use;
\r
19 float race_GetTime(float pos);
\r
20 string race_GetName(float pos);
\r
21 string race_PlaceName(float pos);
\r
22 string GetMapname();
\r
23 string ColoredTeamName(float t);
\r
25 string admin_name(void)
\r
27 if(cvar_string("sv_adminnick") != "")
\r
28 return cvar_string("sv_adminnick");
\r
30 return "SERVER ADMIN";
\r
33 float DistributeEvenly_amount;
\r
34 float DistributeEvenly_totalweight;
\r
35 void DistributeEvenly_Init(float amount, float totalweight)
\r
37 if (DistributeEvenly_amount)
\r
39 dprint("DistributeEvenly_Init: UNFINISHED DISTRIBUTION (", ftos(DistributeEvenly_amount), " for ");
\r
40 dprint(ftos(DistributeEvenly_totalweight), " left!)\n");
\r
42 if (totalweight == 0)
\r
43 DistributeEvenly_amount = 0;
\r
45 DistributeEvenly_amount = amount;
\r
46 DistributeEvenly_totalweight = totalweight;
\r
48 float DistributeEvenly_Get(float weight)
\r
53 f = floor(0.5 + DistributeEvenly_amount * weight / DistributeEvenly_totalweight);
\r
54 DistributeEvenly_totalweight -= weight;
\r
55 DistributeEvenly_amount -= f;
\r
59 #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
\r
62 string STR_PLAYER = "player";
\r
63 string STR_SPECTATOR = "spectator";
\r
64 string STR_OBSERVER = "observer";
\r
67 #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
\r
68 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
69 #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
\r
70 #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
72 #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
\r
73 #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
\r
74 #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
\r
75 #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
\r
76 #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
\r
79 // copies a string to a tempstring (so one can strunzone it)
\r
80 string strcat1(string s) = #115; // FRIK_FILE
\r
85 string GetAdvancedDeathReports(entity enPlayer) // Extra fragmessage information
\r
87 local float nPlayerHealth = rint(enPlayer.health);
\r
88 local float nPlayerArmor = rint(enPlayer.armorvalue);
\r
89 local float nPlayerHandicap = enPlayer.cvar_cl_handicap;
\r
90 local float nPlayerPing = rint(enPlayer.ping);
\r
91 local string strPlayerPingColor;
\r
92 local string strMessage;
\r
93 if(nPlayerPing >= 150)
\r
94 strPlayerPingColor = "^1";
\r
96 strPlayerPingColor = "^2";
\r
98 if((cvar("sv_fragmessage_information_stats")) && (enPlayer.health >= 1))
\r
99 strMessage = strcat(strMessage, "\n^7(Health ^1", ftos(nPlayerHealth), "^7 / Armor ^2", ftos(nPlayerArmor), "^7)");
\r
101 if(cvar("sv_fragmessage_information_ping")) {
\r
102 if(clienttype(enPlayer) == CLIENTTYPE_BOT) // Bots have no ping
\r
103 strMessage = strcat(strMessage, "\n^7(^2Bot");
\r
105 strMessage = strcat(strMessage, "\n^7(Ping ", strPlayerPingColor, ftos(nPlayerPing), "ms");
\r
106 if(cvar("sv_fragmessage_information_handicap"))
\r
107 if(cvar("sv_fragmessage_information_handicap") == 2)
\r
108 if(nPlayerHandicap <= 1)
\r
109 strMessage = strcat(strMessage, "^7 / Handicap ^2Off^7)");
\r
111 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
112 else if not(nPlayerHandicap <= 1)
\r
113 strMessage = strcat(strMessage, "^7 / Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
115 strMessage = strcat(strMessage, "^7)");
\r
116 } else if(cvar("sv_fragmessage_information_handicap")) {
\r
117 if(cvar("sv_fragmessage_information_handicap") == 2)
\r
118 if(nPlayerHandicap <= 1)
\r
119 strMessage = strcat(strMessage, "\n^7(Handicap ^2Off^7)");
\r
121 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
122 else if(nPlayerHandicap > 1)
\r
123 strMessage = strcat(strMessage, "\n^7(Handicap ^2", ftos(nPlayerHandicap), "^7)");
\r
127 void bcenterprint(string s)
\r
129 // TODO replace by MSG_ALL (would show it to spectators too, though)?
\r
131 FOR_EACH_PLAYER(head)
\r
132 if (clienttype(head) == CLIENTTYPE_REAL)
\r
133 centerprint(head, s);
\r
136 void GameLogEcho(string s)
\r
141 if (cvar("sv_eventlog_files"))
\r
145 logfile_open = TRUE;
\r
146 matches = cvar("sv_eventlog_files_counter") + 1;
\r
147 cvar_set("sv_eventlog_files_counter", ftos(matches));
\r
148 fn = ftos(matches);
\r
149 if (strlen(fn) < 8)
\r
150 fn = strcat(substring("00000000", 0, 8 - strlen(fn)), fn);
\r
151 fn = strcat(cvar_string("sv_eventlog_files_nameprefix"), fn, cvar_string("sv_eventlog_files_namesuffix"));
\r
152 logfile = fopen(fn, FILE_APPEND);
\r
153 fputs(logfile, ":logversion:3\n");
\r
157 if (cvar("sv_eventlog_files_timestamps"))
\r
158 fputs(logfile, strcat(":time:", strftime(TRUE, "%Y-%m-%d %H:%M:%S", "\n", s, "\n")));
\r
160 fputs(logfile, strcat(s, "\n"));
\r
163 if (cvar("sv_eventlog_console"))
\r
172 // will be opened later
\r
175 void GameLogClose()
\r
177 if (logfile_open && logfile >= 0)
\r
184 vector PL_VIEW_OFS;
\r
187 vector PL_CROUCH_VIEW_OFS;
\r
188 vector PL_CROUCH_MIN;
\r
189 vector PL_CROUCH_MAX;
\r
191 float spawnpoint_nag;
\r
192 void relocate_spawnpoint()
\r
194 PL_VIEW_OFS = stov(cvar_string("sv_player_viewoffset"));
\r
195 PL_MIN = stov(cvar_string("sv_player_mins"));
\r
196 PL_MAX = stov(cvar_string("sv_player_maxs"));
\r
197 PL_CROUCH_VIEW_OFS = stov(cvar_string("sv_player_crouch_viewoffset"));
\r
198 PL_CROUCH_MIN = stov(cvar_string("sv_player_crouch_mins"));
\r
199 PL_CROUCH_MAX = stov(cvar_string("sv_player_crouch_maxs"));
\r
201 // nudge off the floor
\r
202 setorigin(self, self.origin + '0 0 1');
\r
204 tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
\r
205 if (trace_startsolid)
\r
209 self.mins = PL_MIN;
\r
210 self.maxs = PL_MAX;
\r
211 if (!move_out_of_solid(self))
\r
212 objerror("could not get out of solid at all!");
\r
213 print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
\r
214 print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
\r
215 print(" ", ftos(self.origin_y - o_y));
\r
216 print(" ", ftos(self.origin_z - o_z), "'\n");
\r
217 if (cvar("g_spawnpoints_auto_move_out_of_solid"))
\r
219 if (!spawnpoint_nag)
\r
220 print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
\r
221 spawnpoint_nag = 1;
\r
225 setorigin(self, o);
\r
226 self.mins = self.maxs = '0 0 0';
\r
227 objerror("player spawn point in solid, mapper sucks!\n");
\r
232 if (cvar("g_spawnpoints_autodrop"))
\r
234 setsize(self, PL_MIN, PL_MAX);
\r
238 self.use = spawnpoint_use;
\r
239 self.team_saved = self.team;
\r
243 if (have_team_spawns != 0)
\r
245 have_team_spawns = 1;
\r
247 if (cvar("r_showbboxes"))
\r
249 // show where spawnpoints point at too
\r
250 makevectors(self.angles);
\r
253 e.classname = "info_player_foo";
\r
254 setorigin(e, self.origin + v_forward * 24);
\r
255 setsize(e, '-8 -8 -8', '8 8 8');
\r
256 e.solid = SOLID_TRIGGER;
\r
260 #define strstr strstrofs
\r
262 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
\r
263 // IT WILL MOST PROBABLY DESTROY _ALL_ OTHER TEMP
\r
264 // STRINGS AND TAKE QUITE LONG. haystack and needle MUST
\r
265 // BE CONSTANT OR strzoneD!
\r
266 float strstr(string haystack, string needle, float offset)
\r
270 len = strlen(needle);
\r
271 endpos = strlen(haystack) - len;
\r
272 while(offset <= endpos)
\r
274 found = substring(haystack, offset, len);
\r
275 if(found == needle)
\r
277 offset = offset + 1;
\r
283 float NUM_NEAREST_ENTITIES = 4;
\r
284 entity nearest_entity[NUM_NEAREST_ENTITIES];
\r
285 float nearest_length[NUM_NEAREST_ENTITIES];
\r
286 entity findnearest(vector point, .string field, string value, vector axismod)
\r
297 localhead = find(world, field, value);
\r
300 if ((localhead.items == IT_KEY1 || localhead.items == IT_KEY2) && localhead.target == "###item###")
\r
301 dist = localhead.oldorigin;
\r
303 dist = localhead.origin;
\r
304 dist = dist - point;
\r
305 dist = dist_x * axismod_x * '1 0 0' + dist_y * axismod_y * '0 1 0' + dist_z * axismod_z * '0 0 1';
\r
308 for (i = 0; i < num_nearest; ++i)
\r
310 if (len < nearest_length[i])
\r
314 // now i tells us where to insert at
\r
315 // INSERTION SORT! YOU'VE SEEN IT! RUN!
\r
316 if (i < NUM_NEAREST_ENTITIES)
\r
318 for (j = NUM_NEAREST_ENTITIES - 1; j >= i; --j)
\r
320 nearest_length[j + 1] = nearest_length[j];
\r
321 nearest_entity[j + 1] = nearest_entity[j];
\r
323 nearest_length[i] = len;
\r
324 nearest_entity[i] = localhead;
\r
325 if (num_nearest < NUM_NEAREST_ENTITIES)
\r
326 num_nearest = num_nearest + 1;
\r
329 localhead = find(localhead, field, value);
\r
332 // now use the first one from our list that we can see
\r
333 for (i = 0; i < num_nearest; ++i)
\r
335 traceline(point, nearest_entity[i].origin, TRUE, world);
\r
336 if (trace_fraction == 1)
\r
340 dprint("Nearest point (");
\r
341 dprint(nearest_entity[0].netname);
\r
342 dprint(") is not visible, using a visible one.\n");
\r
344 return nearest_entity[i];
\r
348 if (num_nearest == 0)
\r
351 dprint("Not seeing any location point, using nearest as fallback.\n");
\r
353 dprint("Candidates were: ");
\r
354 for(j = 0; j < num_nearest; ++j)
\r
358 dprint(nearest_entity[j].netname);
\r
363 return nearest_entity[0];
\r
366 void spawnfunc_target_location()
\r
368 self.classname = "target_location";
\r
369 // location name in netname
\r
370 // eventually support: count, teamgame selectors, line of sight?
\r
373 void spawnfunc_info_location()
\r
375 self.classname = "target_location";
\r
376 self.message = self.netname;
\r
379 string NearestLocation(vector p)
\r
384 loc = findnearest(p, classname, "target_location", '1 1 1');
\r
391 loc = findnearest(p, target, "###item###", '1 1 4');
\r
398 string formatmessage(string msg)
\r
405 string replacement;
\r
409 WarpZone_crosshair_trace(self);
\r
410 cursor = trace_endpos;
\r
411 cursor_ent = trace_ent;
\r
415 break; // too many replacements
\r
418 p1 = strstr(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
\r
419 p2 = strstr(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
\r
432 replacement = substring(msg, p, 2);
\r
433 escape = substring(msg, p + 1, 1);
\r
437 else if (escape == "\\")
\r
438 replacement = "\\";
\r
439 else if (escape == "n")
\r
440 replacement = "\n";
\r
441 else if (escape == "a")
\r
442 replacement = ftos(floor(self.armorvalue));
\r
443 else if (escape == "h")
\r
444 replacement = ftos(floor(self.health));
\r
445 else if (escape == "l")
\r
446 replacement = NearestLocation(self.origin);
\r
447 else if (escape == "y")
\r
448 replacement = NearestLocation(cursor);
\r
449 else if (escape == "d")
\r
450 replacement = NearestLocation(self.death_origin);
\r
451 else if (escape == "w") {
\r
455 wep = self.switchweapon;
\r
458 replacement = W_Name(wep);
\r
459 } else if (escape == "W") {
\r
460 replacement = "batteries"; // ;)
\r
461 } else if (escape == "x") {
\r
462 replacement = cursor_ent.netname;
\r
463 if (!replacement || !cursor_ent)
\r
464 replacement = "nothing";
\r
465 } else if (escape == "p") {
\r
466 if (self.last_selected_player)
\r
467 replacement = self.last_selected_player.netname;
\r
469 replacement = "(nobody)";
\r
470 } else if (escape == "s")
\r
471 replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
\r
472 else if (escape == "S")
\r
473 replacement = ftos(vlen(self.velocity));
\r
474 else if (escape == "v") {
\r
475 float weapon_number;
\r
476 local entity stats;
\r
478 if(self.classname == "spectator")
\r
479 stats = self.enemy;
\r
483 weapon_number = stats.weapon;
\r
485 if (!weapon_number)
\r
486 weapon_number = stats.switchweapon;
\r
488 if (!weapon_number)
\r
489 weapon_number = stats.cnt;
\r
491 if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
\r
492 replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
\r
494 replacement = "~"; // or something to indicate NULL, not available
\r
497 msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
\r
498 p = p + strlen(replacement);
\r
503 float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1)
\r
504 return (value == 0) ? FALSE : TRUE;
\r
512 0: sends the request
\r
513 >0: receives a cvar from name=argv(f) value=argv(f+1)
\r
515 void GetCvars_handleString(string thisname, float f, .string field, string name)
\r
520 strunzone(self.field);
\r
521 self.field = string_null;
\r
525 if (thisname == name)
\r
528 strunzone(self.field);
\r
529 self.field = strzone(argv(f + 1));
\r
533 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
535 void GetCvars_handleString_Fixup(string thisname, float f, .string field, string name, string(string) func)
\r
537 GetCvars_handleString(thisname, f, field, name);
\r
538 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
\r
539 if (thisname == name)
\r
542 s = func(strcat1(self.field));
\r
543 if (s != self.field)
\r
545 strunzone(self.field);
\r
546 self.field = strzone(s);
\r
550 void GetCvars_handleFloat(string thisname, float f, .float field, string name)
\r
557 if (thisname == name)
\r
558 self.field = stof(argv(f + 1));
\r
561 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
563 void GetCvars_handleFloatOnce(string thisname, float f, .float field, string name)
\r
570 if (thisname == name)
\r
574 self.field = stof(argv(f + 1));
\r
583 stuffcmd(self, strcat("sendcvar ", name, "\n"));
\r
586 string W_FixWeaponOrder_ForceComplete(string s);
\r
587 string W_FixWeaponOrder_AllowIncomplete(string s);
\r
588 float w_getbestweapon(entity e);
\r
589 void GetCvars(float f)
\r
593 s = strcat1(argv(f));
\r
594 GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
\r
595 GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
\r
596 GetCvars_handleFloat(s, f, cvar_cl_shownames, "cl_shownames");
\r
597 GetCvars_handleString(s, f, cvar_g_voretournamentversion, "g_voretournamentversion");
\r
598 GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
\r
599 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete);
\r
600 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
\r
601 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
\r
602 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
\r
603 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
\r
604 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
\r
605 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
\r
606 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
\r
607 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
\r
608 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
\r
609 GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
\r
610 GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt");
\r
611 GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag");
\r
612 GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional");
\r
613 GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation");
\r
614 GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound");
\r
615 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share");
\r
616 GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive");
\r
617 GetCvars_handleFloat(s, f, cvar_chase_active, "chase_active");
\r
618 GetCvars_handleFloat(s, f, cvar_cl_vore_stomachmodel, "cl_vore_stomachmodel");
\r
619 GetCvars_handleFloat(s, f, cvar_cl_vore_cameraspeed, "cl_vore_cameraspeed");
\r
620 GetCvars_handleFloat(s, f, cvar_cl_vore_punchangle, "cl_vore_punchangle");
\r
621 GetCvars_handleFloat(s, f, cvar_cl_vore_kick_punchangle, "cl_vore_kick_punchangle");
\r
622 GetCvars_handleFloat(s, f, cvar_cl_vore_autodigest, "cl_vore_autodigest");
\r
624 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
\r
625 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
\r
627 #ifdef ALLOW_FORCEMODELS
\r
628 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
\r
629 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromvoretournament, "cl_forceplayermodelsfromvoretournament");
\r
631 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
\r
633 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
\r
636 if (s == "cl_weaponpriority")
\r
637 self.switchweapon = w_getbestweapon(self);
\r
641 float fexists(string f)
\r
644 fh = fopen(f, FILE_READ);
\r
651 void backtrace(string msg)
\r
654 dev = cvar("developer");
\r
655 war = cvar("prvm_backtraceforwarnings");
\r
656 cvar_set("developer", "1");
\r
657 cvar_set("prvm_backtraceforwarnings", "1");
\r
659 print("--- CUT HERE ---\nWARNING: ");
\r
662 remove(world); // isn't there any better way to cause a backtrace?
\r
663 print("\n--- CUT UNTIL HERE ---\n");
\r
664 cvar_set("developer", ftos(dev));
\r
665 cvar_set("prvm_backtraceforwarnings", ftos(war));
\r
668 string Team_ColorCode(float teamid)
\r
670 if (teamid == COLOR_TEAM1)
\r
672 else if (teamid == COLOR_TEAM2)
\r
674 else if (teamid == COLOR_TEAM3)
\r
676 else if (teamid == COLOR_TEAM4)
\r
682 string Team_ColorName(float t)
\r
684 // fixme: Search for team entities and get their .netname's!
\r
685 if (t == COLOR_TEAM1)
\r
687 if (t == COLOR_TEAM2)
\r
689 if (t == COLOR_TEAM3)
\r
691 if (t == COLOR_TEAM4)
\r
696 string Team_ColorNameLowerCase(float t)
\r
698 // fixme: Search for team entities and get their .netname's!
\r
699 if (t == COLOR_TEAM1)
\r
701 if (t == COLOR_TEAM2)
\r
703 if (t == COLOR_TEAM3)
\r
705 if (t == COLOR_TEAM4)
\r
710 float ColourToNumber(string team_colour)
\r
712 if (team_colour == "red")
\r
713 return COLOR_TEAM1;
\r
715 if (team_colour == "blue")
\r
716 return COLOR_TEAM2;
\r
718 if (team_colour == "yellow")
\r
719 return COLOR_TEAM3;
\r
721 if (team_colour == "pink")
\r
722 return COLOR_TEAM4;
\r
724 if (team_colour == "auto")
\r
730 float NumberToTeamNumber(float number)
\r
733 return COLOR_TEAM1;
\r
736 return COLOR_TEAM2;
\r
739 return COLOR_TEAM3;
\r
742 return COLOR_TEAM4;
\r
747 #define CENTERPRIO_POINT 1
\r
748 #define CENTERPRIO_SPAM 2
\r
749 #define CENTERPRIO_VOTE 4
\r
750 #define CENTERPRIO_NORMAL 5
\r
751 #define CENTERPRIO_SHIELDING 7
\r
752 #define CENTERPRIO_MAPVOTE 9
\r
753 #define CENTERPRIO_IDLEKICK 50
\r
754 #define CENTERPRIO_ADMIN 99
\r
755 .float centerprint_priority;
\r
756 .float centerprint_expires;
\r
757 void centerprint_atprio(entity e, float prio, string s)
\r
759 if (intermission_running)
\r
760 if (prio < CENTERPRIO_MAPVOTE)
\r
762 if (time > e.centerprint_expires)
\r
763 e.centerprint_priority = 0;
\r
764 if (prio >= e.centerprint_priority)
\r
766 e.centerprint_priority = prio;
\r
767 if (timeoutStatus == 2)
\r
768 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
\r
770 e.centerprint_expires = time + e.cvar_scr_centertime;
\r
771 centerprint_builtin(e, s);
\r
774 void centerprint_expire(entity e, float prio)
\r
776 if (prio == e.centerprint_priority)
\r
778 e.centerprint_priority = 0;
\r
779 centerprint_builtin(e, "");
\r
782 void centerprint(entity e, string s)
\r
784 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
\r
787 // decolorizes and team colors the player name when needed
\r
788 string playername(entity p)
\r
791 if (teams_matter && !intermission_running && p.classname == "player")
\r
793 t = Team_ColorCode(p.team);
\r
794 return strcat(t, strdecolorize(p.netname));
\r
800 vector randompos(vector m1, vector m2)
\r
804 v_x = m2_x * random() + m1_x;
\r
805 v_y = m2_y * random() + m1_y;
\r
806 v_z = m2_z * random() + m1_z;
\r
810 float g_pickup_fuel;
\r
811 float g_pickup_fuel_jetpack;
\r
812 float g_pickup_fuel_max;
\r
813 float g_pickup_armorsmall;
\r
814 float g_pickup_armorsmall_max;
\r
815 float g_pickup_armormedium;
\r
816 float g_pickup_armormedium_max;
\r
817 float g_pickup_armorbig;
\r
818 float g_pickup_armorbig_max;
\r
819 float g_pickup_armorlarge;
\r
820 float g_pickup_armorlarge_max;
\r
821 float g_pickup_healthsmall;
\r
822 float g_pickup_healthsmall_max;
\r
823 float g_pickup_healthmedium;
\r
824 float g_pickup_healthmedium_max;
\r
825 float g_pickup_healthlarge;
\r
826 float g_pickup_healthlarge_max;
\r
827 float g_pickup_healthmega;
\r
828 float g_pickup_healthmega_max;
\r
829 float g_weaponspeedfactor;
\r
830 float g_weaponratefactor;
\r
831 float g_weapondamagefactor;
\r
832 float g_weaponforcefactor;
\r
833 float g_weaponspreadfactor;
\r
835 float start_weapons;
\r
837 float start_ammo_fuel;
\r
838 float start_health;
\r
839 float start_armorvalue;
\r
840 float warmup_start_weapons;
\r
841 float warmup_start_ammo_fuel;
\r
842 float warmup_start_health;
\r
843 float warmup_start_armorvalue;
\r
844 float g_weapon_stay;
\r
845 float g_ghost_items;
\r
847 entity get_weaponinfo(float w);
\r
849 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
\r
851 var float i = weaponinfo.weapon;
\r
856 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
\r
858 if (t < 0) // "default" weapon selection
\r
860 if(g_rpg) // no start weapons in RPG by default
\r
863 t = (i == WEP_GRABBER);
\r
869 void readplayerstartcvars()
\r
874 // initialize starting values for players
\r
877 start_health = cvar("g_balance_health_start");
\r
878 start_armorvalue = cvar("g_balance_armor_start");
\r
882 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
\r
883 start_health = cvar("g_lms_start_health");
\r
884 start_armorvalue = cvar("g_lms_start_armor");
\r
886 else if (cvar("g_use_ammunition"))
\r
888 start_ammo_fuel = cvar("g_start_ammo_fuel");
\r
892 start_ammo_fuel = cvar("g_pickup_fuel_max");
\r
893 start_items |= IT_UNLIMITED_AMMO;
\r
896 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
898 e = get_weaponinfo(i);
\r
899 if(want_weapon("g_start_weapon_", e, FALSE))
\r
901 start_weapons |= e.weapons;
\r
902 weapon_action(e.weapon, WR_PRECACHE);
\r
908 warmup_start_ammo_fuel = start_ammo_fuel;
\r
909 warmup_start_health = start_health;
\r
910 warmup_start_armorvalue = start_armorvalue;
\r
911 warmup_start_weapons = start_weapons;
\r
913 if (cvar("g_use_ammunition"))
\r
915 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
\r
917 warmup_start_health = cvar("g_warmup_start_health");
\r
918 warmup_start_armorvalue = cvar("g_warmup_start_armor");
\r
919 warmup_start_weapons = 0;
\r
920 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
922 e = get_weaponinfo(i);
\r
923 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
\r
925 warmup_start_weapons |= e.weapons;
\r
926 weapon_action(e.weapon, WR_PRECACHE);
\r
933 start_items |= IT_FUEL_REGEN;
\r
934 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
935 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
939 start_items |= IT_JETPACK;
\r
941 if (g_weapon_stay == 2)
\r
943 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
\r
944 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
\r
947 start_ammo_fuel = max(0, start_ammo_fuel);
\r
949 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
\r
953 float g_bugrigs_planar_movement;
\r
954 float g_bugrigs_planar_movement_car_jumping;
\r
955 float g_bugrigs_reverse_spinning;
\r
956 float g_bugrigs_reverse_speeding;
\r
957 float g_bugrigs_reverse_stopping;
\r
958 float g_bugrigs_air_steering;
\r
959 float g_bugrigs_angle_smoothing;
\r
960 float g_bugrigs_friction_floor;
\r
961 float g_bugrigs_friction_brake;
\r
962 float g_bugrigs_friction_air;
\r
963 float g_bugrigs_accel;
\r
964 float g_bugrigs_speed_ref;
\r
965 float g_bugrigs_speed_pow;
\r
966 float g_bugrigs_steer;
\r
968 float g_touchexplode;
\r
969 float g_touchexplode_radius;
\r
970 float g_touchexplode_damage;
\r
971 float g_touchexplode_edgedamage;
\r
972 float g_touchexplode_force;
\r
974 float sv_autotaunt;
\r
977 float sv_pitch_min;
\r
978 float sv_pitch_max;
\r
979 float sv_pitch_fixyaw;
\r
981 float sv_accuracy_data_share;
\r
983 void readlevelcvars(void)
\r
985 g_bugrigs = cvar("g_bugrigs");
\r
986 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
\r
987 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
\r
988 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
\r
989 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
\r
990 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
\r
991 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
\r
992 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
\r
993 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
\r
994 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
\r
995 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
\r
996 g_bugrigs_accel = cvar("g_bugrigs_accel");
\r
997 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
\r
998 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
\r
999 g_bugrigs_steer = cvar("g_bugrigs_steer");
\r
1001 g_touchexplode = cvar("g_touchexplode");
\r
1002 g_touchexplode_radius = cvar("g_touchexplode_radius");
\r
1003 g_touchexplode_damage = cvar("g_touchexplode_damage");
\r
1004 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
\r
1005 g_touchexplode_force = cvar("g_touchexplode_force");
\r
1007 #ifdef ALLOW_FORCEMODELS
\r
1008 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
\r
1011 sv_clones = cvar("sv_clones");
\r
1012 sv_gentle = cvar("sv_gentle");
\r
1013 sv_foginterval = cvar("sv_foginterval");
\r
1014 g_cloaked = cvar("g_cloaked");
\r
1015 g_jump_grunt = cvar("g_jump_grunt");
\r
1016 g_footsteps = cvar("g_footsteps");
\r
1017 g_jetpack = cvar("g_jetpack");
\r
1018 g_midair = cvar("g_midair");
\r
1019 g_norecoil = cvar("g_norecoil");
\r
1020 g_vampire = cvar("g_vampire");
\r
1021 g_bloodloss = cvar("g_bloodloss");
\r
1022 sv_maxidle = cvar("sv_maxidle");
\r
1023 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
\r
1024 sv_pogostick = cvar("sv_pogostick");
\r
1025 sv_doublejump = cvar("sv_doublejump");
\r
1026 g_ctf_reverse = cvar("g_ctf_reverse");
\r
1027 sv_autotaunt = cvar("sv_autotaunt");
\r
1028 sv_taunt = cvar("sv_taunt");
\r
1030 inWarmupStage = cvar("g_warmup");
\r
1031 g_warmup_limit = cvar("g_warmup_limit");
\r
1032 g_warmup_allguns = cvar("g_warmup_allguns");
\r
1033 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
\r
1035 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
\r
1036 inWarmupStage = 0; // these modes cannot work together, sorry
\r
1038 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
\r
1039 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
\r
1040 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
\r
1041 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
\r
1042 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
\r
1043 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
\r
1044 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
\r
1045 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
\r
1046 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
\r
1047 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
\r
1048 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
\r
1049 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
\r
1051 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
\r
1052 g_weaponratefactor = cvar("g_weaponratefactor");
\r
1053 g_weapondamagefactor = cvar("g_weapondamagefactor");
\r
1054 g_weaponforcefactor = cvar("g_weaponforcefactor");
\r
1055 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
\r
1057 g_pickup_fuel = cvar("g_pickup_fuel");
\r
1058 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
\r
1059 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
\r
1060 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
\r
1061 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
\r
1062 g_pickup_armormedium = cvar("g_pickup_armormedium");
\r
1063 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
\r
1064 g_pickup_armorbig = cvar("g_pickup_armorbig");
\r
1065 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
\r
1066 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
\r
1067 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
\r
1068 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
\r
1069 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
\r
1070 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
\r
1071 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
\r
1072 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
\r
1073 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
\r
1074 g_pickup_healthmega = cvar("g_pickup_healthmega");
\r
1075 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
\r
1077 g_weapon_stay = cvar("g_weapon_stay");
\r
1079 if (!g_weapon_stay && (cvar("deathmatch") == 2))
\r
1080 g_weapon_stay = 1;
\r
1082 g_ghost_items = cvar("g_ghost_items");
\r
1084 if(g_ghost_items >= 1)
\r
1085 g_ghost_items = 0.25; // default alpha value
\r
1087 if not(inWarmupStage && !g_ca)
\r
1088 game_starttime = cvar("g_start_delay");
\r
1090 sv_pitch_min = cvar("sv_pitch_min");
\r
1091 sv_pitch_max = cvar("sv_pitch_max");
\r
1092 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
\r
1094 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
\r
1096 readplayerstartcvars();
\r
1100 // TODO sound pack system
\r
1103 string precache_sound_builtin (string s) = #19;
\r
1104 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1105 string precache_sound(string s)
\r
1107 return precache_sound_builtin(strcat(soundpack, s));
\r
1109 void play2(entity e, string filename)
\r
1111 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
\r
1113 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1115 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
\r
1119 // Sound functions
\r
1120 string precache_sound (string s) = #19;
\r
1121 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1122 float precache_sound_index (string s) = #19;
\r
1124 #define SND_VOLUME 1
\r
1125 #define SND_ATTENUATION 2
\r
1126 #define SND_LARGEENTITY 8
\r
1127 #define SND_LARGESOUND 16
\r
1129 float sound_allowed(float dest, entity e)
\r
1131 // sounds from world may always pass
\r
1134 if (e.classname == "body")
\r
1136 if (e.owner && e.owner != e)
\r
1141 // sounds to self may always pass
\r
1142 if (dest == MSG_ONE)
\r
1143 if (e == msg_entity)
\r
1145 // sounds by players can be removed
\r
1146 if (cvar("bot_sound_monopoly"))
\r
1147 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1149 // anything else may pass
\r
1153 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1155 if (!sound_allowed(MSG_BROADCAST, e))
\r
1157 sound_builtin(e, chan, samp, vol, atten);
\r
1159 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
\r
1163 if (!sound_allowed(dest, e))
\r
1166 entno = num_for_edict(e);
\r
1167 idx = precache_sound_index(samp);
\r
1172 atten = floor(atten * 64);
\r
1173 vol = floor(vol * 255);
\r
1176 sflags |= SND_VOLUME;
\r
1178 sflags |= SND_ATTENUATION;
\r
1179 if (entno >= 8192)
\r
1180 sflags |= SND_LARGEENTITY;
\r
1182 sflags |= SND_LARGESOUND;
\r
1184 WriteByte(dest, SVC_SOUND);
\r
1185 WriteByte(dest, sflags);
\r
1186 if (sflags & SND_VOLUME)
\r
1187 WriteByte(dest, vol);
\r
1188 if (sflags & SND_ATTENUATION)
\r
1189 WriteByte(dest, atten);
\r
1190 if (sflags & SND_LARGEENTITY)
\r
1192 WriteShort(dest, entno);
\r
1193 WriteByte(dest, chan);
\r
1197 WriteShort(dest, entno * 8 + chan);
\r
1199 if (sflags & SND_LARGESOUND)
\r
1200 WriteShort(dest, idx);
\r
1202 WriteByte(dest, idx);
\r
1204 WriteCoord(dest, o_x);
\r
1205 WriteCoord(dest, o_y);
\r
1206 WriteCoord(dest, o_z);
\r
1208 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
\r
1212 if (!sound_allowed(dest, e))
\r
1215 o = e.origin + 0.5 * (e.mins + e.maxs);
\r
1216 soundtoat(dest, e, o, chan, samp, vol, atten);
\r
1218 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
\r
1220 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
\r
1222 void stopsoundto(float dest, entity e, float chan)
\r
1226 if (!sound_allowed(dest, e))
\r
1229 entno = num_for_edict(e);
\r
1231 if (entno >= 8192)
\r
1233 float idx, sflags;
\r
1234 idx = precache_sound_index("misc/null.wav");
\r
1235 sflags = SND_LARGEENTITY;
\r
1237 sflags |= SND_LARGESOUND;
\r
1238 WriteByte(dest, SVC_SOUND);
\r
1239 WriteByte(dest, sflags);
\r
1240 WriteShort(dest, entno);
\r
1241 WriteByte(dest, chan);
\r
1242 if (sflags & SND_LARGESOUND)
\r
1243 WriteShort(dest, idx);
\r
1245 WriteByte(dest, idx);
\r
1246 WriteCoord(dest, e.origin_x);
\r
1247 WriteCoord(dest, e.origin_y);
\r
1248 WriteCoord(dest, e.origin_z);
\r
1252 WriteByte(dest, SVC_STOPSOUND);
\r
1253 WriteShort(dest, entno * 8 + chan);
\r
1256 void stopsound(entity e, float chan)
\r
1258 if (!sound_allowed(MSG_BROADCAST, e))
\r
1261 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
\r
1262 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
\r
1265 void play2(entity e, string filename)
\r
1267 //stuffcmd(e, strcat("play2 ", filename, "\n"));
\r
1268 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1271 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
\r
1275 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
\r
1277 float spamsound(entity e, float chan, string samp, float vol, float atten)
\r
1279 if (!sound_allowed(MSG_BROADCAST, e))
\r
1282 if (time > e.spamtime)
\r
1284 e.spamtime = time;
\r
1285 sound(e, chan, samp, vol, atten);
\r
1291 void play2team(float t, string filename)
\r
1293 local entity head;
\r
1295 if (cvar("bot_sound_monopoly"))
\r
1298 FOR_EACH_REALPLAYER(head)
\r
1300 if (head.team == t)
\r
1301 play2(head, filename);
\r
1305 void play2all(string samp)
\r
1307 if (cvar("bot_sound_monopoly"))
\r
1310 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
\r
1313 void PrecachePlayerSounds(string f);
\r
1314 void precache_all_models(string pattern)
\r
1316 float globhandle, i, n;
\r
1319 globhandle = search_begin(pattern, TRUE, FALSE);
\r
1320 if (globhandle < 0)
\r
1322 n = search_getsize(globhandle);
\r
1323 for (i = 0; i < n; ++i)
\r
1325 //print(search_getfilename(globhandle, i), "\n");
\r
1326 f = search_getfilename(globhandle, i);
\r
1327 precache_model(f);
\r
1328 PrecachePlayerSounds(strcat(f, ".sounds"));
\r
1330 search_end(globhandle);
\r
1335 // gamemode related things
\r
1336 precache_model ("models/misc/chatbubble.spr");
\r
1337 precache_model ("models/misc/teambubble.spr");
\r
1338 precache_model ("models/misc/teambubbleheal.spr");
\r
1340 // used by the waypoint editor
\r
1341 precache_model ("models/rune.mdl");
\r
1343 #ifdef TTURRETS_ENABLED
\r
1344 if (cvar("g_turrets"))
\r
1345 turrets_precash();
\r
1348 // Precache all player models if desired
\r
1349 if (cvar("sv_precacheplayermodels"))
\r
1351 PrecachePlayerSounds("sound/player/default.sounds");
\r
1352 precache_all_models("models/player/*.zym");
\r
1353 precache_all_models("models/player/*.dpm");
\r
1354 precache_all_models("models/player/*.md3");
\r
1355 precache_all_models("models/player/*.psk");
\r
1356 //precache_model("models/player/vixen.zym");
\r
1359 if (cvar("sv_defaultcharacter"))
\r
1362 s = cvar_string("sv_defaultplayermodel_red");
\r
1365 precache_model(s);
\r
1366 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1368 s = cvar_string("sv_defaultplayermodel_blue");
\r
1371 precache_model(s);
\r
1372 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1374 s = cvar_string("sv_defaultplayermodel_yellow");
\r
1377 precache_model(s);
\r
1378 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1380 s = cvar_string("sv_defaultplayermodel_pink");
\r
1383 precache_model(s);
\r
1384 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1386 s = cvar_string("sv_defaultplayermodel");
\r
1389 precache_model(s);
\r
1390 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1396 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
\r
1397 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
\r
1400 // gore and miscellaneous sounds
\r
1401 //precache_sound ("misc/h2ohit.wav");
\r
1402 precache_model ("models/grabber.md3");
\r
1403 precache_sound ("misc/armorimpact.wav");
\r
1404 precache_sound ("misc/bodyimpact1.wav");
\r
1405 precache_sound ("misc/bodyimpact2.wav");
\r
1406 precache_sound ("misc/gib.wav");
\r
1407 precache_sound ("misc/gib_splat01.wav");
\r
1408 precache_sound ("misc/gib_splat02.wav");
\r
1409 precache_sound ("misc/gib_splat03.wav");
\r
1410 precache_sound ("misc/gib_splat04.wav");
\r
1411 precache_sound ("misc/hit.wav");
\r
1412 precache_sound ("misc/typehit.wav");
\r
1413 precache_sound ("misc/unavailable.wav");
\r
1414 precache_sound ("misc/forbidden.wav");
\r
1415 precache_sound ("misc/beep.ogg");
\r
1416 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
\r
1417 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
\r
1418 precache_sound ("misc/null.wav");
\r
1419 precache_sound ("misc/spawn.wav");
\r
1420 precache_sound ("misc/talk.wav");
\r
1421 precache_sound ("misc/teleport.wav");
\r
1422 precache_sound ("misc/poweroff.wav");
\r
1423 precache_sound ("player/lava.wav");
\r
1424 precache_sound ("player/slime.wav");
\r
1425 precache_sound ("player/digest.wav");
\r
1426 precache_sound ("misc/health_regen.ogg");
\r
1427 precache_sound ("misc/armor_regen.ogg");
\r
1430 precache_sound ("misc/jetpack_fly.wav");
\r
1432 precache_model ("models/sprites/0.spr32");
\r
1433 precache_model ("models/sprites/1.spr32");
\r
1434 precache_model ("models/sprites/2.spr32");
\r
1435 precache_model ("models/sprites/3.spr32");
\r
1436 precache_model ("models/sprites/4.spr32");
\r
1437 precache_model ("models/sprites/5.spr32");
\r
1438 precache_model ("models/sprites/6.spr32");
\r
1439 precache_model ("models/sprites/7.spr32");
\r
1440 precache_model ("models/sprites/8.spr32");
\r
1441 precache_model ("models/sprites/9.spr32");
\r
1442 precache_model ("models/sprites/10.spr32");
\r
1444 // common weapon precaches
\r
1445 precache_sound ("weapons/weapon_switch.wav");
\r
1446 precache_sound ("weapons/weaponpickup.wav");
\r
1447 precache_sound ("weapons/grabber_fire.wav"); // grabber
\r
1448 precache_sound ("weapons/grabber_altfire.wav"); // grabber
\r
1449 precache_sound ("weapons/grabber_impact.wav"); // grabber
\r
1450 precache_sound ("weapons/stomachkick.ogg");
\r
1452 if (cvar("sv_precacheweapons"))
\r
1454 //precache weapon models/sounds
\r
1457 while (wep <= WEP_LAST)
\r
1459 weapon_action(wep, WR_PRECACHE);
\r
1464 precache_model("models/elaser.mdl");
\r
1465 precache_model("models/laser.mdl");
\r
1466 precache_model("models/ebomb.mdl");
\r
1469 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
\r
1471 if (!self.noise && self.music) // quake 3 uses the music field
\r
1472 self.noise = self.music;
\r
1474 // plays music for the level if there is any
\r
1477 precache_sound (self.noise);
\r
1478 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
\r
1483 // sorry, but using \ in macros breaks line numbers
\r
1484 #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
1485 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
\r
1486 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
\r
1488 // WARNING: this kills the trace globals
\r
1489 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
\r
1490 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
\r
1492 #define INITPRIO_FIRST 0
\r
1493 #define INITPRIO_GAMETYPE 0
\r
1494 #define INITPRIO_GAMETYPE_FALLBACK 1
\r
1495 #define INITPRIO_CVARS 5
\r
1496 #define INITPRIO_FINDTARGET 10
\r
1497 #define INITPRIO_DROPTOFLOOR 20
\r
1498 #define INITPRIO_SETLOCATION 90
\r
1499 #define INITPRIO_LINKDOORS 91
\r
1500 #define INITPRIO_LAST 99
\r
1502 .void(void) initialize_entity;
\r
1503 .float initialize_entity_order;
\r
1504 .entity initialize_entity_next;
\r
1505 entity initialize_entity_first;
\r
1507 void make_safe_for_remove(entity e)
\r
1509 if (e.initialize_entity)
\r
1512 for (ent = initialize_entity_first; ent; )
\r
1514 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
\r
1516 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
\r
1517 // skip it in linked list
\r
1520 prev.initialize_entity_next = ent.initialize_entity_next;
\r
1521 ent = prev.initialize_entity_next;
\r
1525 initialize_entity_first = ent.initialize_entity_next;
\r
1526 ent = initialize_entity_first;
\r
1532 ent = ent.initialize_entity_next;
\r
1538 void objerror(string s)
\r
1540 make_safe_for_remove(self);
\r
1541 objerror_builtin(s);
\r
1544 void remove_unsafely(entity e)
\r
1546 remove_builtin(e);
\r
1549 void remove_safely(entity e)
\r
1551 make_safe_for_remove(e);
\r
1552 remove_builtin(e);
\r
1555 void InitializeEntity(entity e, void(void) func, float order)
\r
1559 if (!e || e.initialize_entity)
\r
1561 // make a proxy initializer entity
\r
1565 e.classname = "initialize_entity";
\r
1569 e.initialize_entity = func;
\r
1570 e.initialize_entity_order = order;
\r
1572 cur = initialize_entity_first;
\r
1575 if (!cur || cur.initialize_entity_order > order)
\r
1577 // insert between prev and cur
\r
1579 prev.initialize_entity_next = e;
\r
1581 initialize_entity_first = e;
\r
1582 e.initialize_entity_next = cur;
\r
1586 cur = cur.initialize_entity_next;
\r
1589 void InitializeEntitiesRun()
\r
1591 entity startoflist;
\r
1592 startoflist = initialize_entity_first;
\r
1593 initialize_entity_first = world;
\r
1594 for (self = startoflist; self; )
\r
1597 var void(void) func;
\r
1598 e = self.initialize_entity_next;
\r
1599 func = self.initialize_entity;
\r
1600 self.initialize_entity_order = 0;
\r
1601 self.initialize_entity = func_null;
\r
1602 self.initialize_entity_next = world;
\r
1603 if (self.classname == "initialize_entity")
\r
1606 e_old = self.enemy;
\r
1607 remove_builtin(self);
\r
1610 //dprint("Delayed initialization: ", self.classname, "\n");
\r
1616 .float uncustomizeentityforclient_set;
\r
1617 .void(void) uncustomizeentityforclient;
\r
1618 void(void) SUB_Nullpointer = #0;
\r
1619 void UncustomizeEntitiesRun()
\r
1623 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
\r
1624 self.uncustomizeentityforclient();
\r
1627 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
\r
1629 e.customizeentityforclient = customizer;
\r
1630 e.uncustomizeentityforclient = uncustomizer;
\r
1631 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
\r
1634 .float nottargeted;
\r
1635 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
\r
1637 void() SUB_Remove;
\r
1638 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
\r
1642 if (e.classname == "")
\r
1643 e.classname = "net_linked";
\r
1645 if (e.model == "" || self.modelindex == 0)
\r
1649 setmodel(e, "null");
\r
1650 setsize(e, mi, ma);
\r
1653 e.SendEntity = sendfunc;
\r
1654 e.SendFlags = 0xFFFFFF;
\r
1657 e.effects |= EF_NODEPTHTEST;
\r
1661 e.nextthink = time + dt;
\r
1662 e.think = SUB_Remove;
\r
1666 void adaptor_think2touch()
\r
1675 void adaptor_think2use()
\r
1680 activator = world;
\r
1687 // deferred dropping
\r
1688 void DropToFloor_Handler()
\r
1690 droptofloor_builtin();
\r
1691 self.dropped_origin = self.origin;
\r
1694 void droptofloor()
\r
1696 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
\r
1701 float trace_hits_box_a0, trace_hits_box_a1;
\r
1703 float trace_hits_box_1d(float end, float thmi, float thma)
\r
1707 // just check if x is in range
\r
1715 // do the trace with respect to x
\r
1716 // 0 -> end has to stay in thmi -> thma
\r
1717 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
\r
1718 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
\r
1719 if (trace_hits_box_a0 > trace_hits_box_a1)
\r
1725 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
\r
1730 // now it is a trace from 0 to end
\r
1732 trace_hits_box_a0 = 0;
\r
1733 trace_hits_box_a1 = 1;
\r
1735 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
\r
1737 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
\r
1739 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
\r
1745 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
\r
1747 return trace_hits_box(start, end, thmi - ma, thma - mi);
\r
1750 float SUB_NoImpactCheck()
\r
1752 // zero hitcontents = this is not the real impact, but either the
\r
1753 // mirror-impact of something hitting the projectile instead of the
\r
1754 // projectile hitting the something, or a touchareagrid one. Neither of
\r
1755 // these stop the projectile from moving, so...
\r
1756 if(trace_dphitcontents == 0)
\r
1758 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
\r
1761 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1763 if (other == world && self.size != '0 0 0')
\r
1766 tic = self.velocity * sys_frametime;
\r
1767 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
\r
1768 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
\r
1769 if (trace_fraction >= 1)
\r
1771 dprint("Odd... did not hit...?\n");
\r
1773 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1775 dprint("Detected and prevented the sky-grapple bug.\n");
\r
1783 #define SUB_OwnerCheck() (other && (other == self.owner))
\r
1785 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
\r
1787 if(SUB_OwnerCheck())
\r
1789 if(SUB_NoImpactCheck())
\r
1794 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
\r
1795 UpdateCSQCProjectileNextFrame(self);
\r
1798 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
\r
1800 float MAX_IPBAN_URIS = 16;
\r
1802 float URI_GET_DISCARD = 0;
\r
1803 float URI_GET_IPBAN = 1;
\r
1804 float URI_GET_IPBAN_END = 16;
\r
1806 void URI_Get_Callback(float id, float status, string data)
\r
1808 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
\r
1810 dprint("\nEnd of data.\n");
\r
1812 if (id == URI_GET_DISCARD)
\r
1816 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
\r
1818 // online ban list
\r
1819 OnlineBanList_URI_Get_Callback(id, status, data);
\r
1823 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
\r
1827 void print_to(entity e, string s)
\r
1830 sprint(e, strcat(s, "\n"));
\r
1835 string getrecords(float page) // 50 records per page
\r
1849 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1851 if (MapInfo_Get_ByID(i))
\r
1853 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
\r
1856 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
\r
1857 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
\r
1865 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1867 if (MapInfo_Get_ByID(i))
\r
1869 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
\r
1872 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
\r
1873 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1881 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1883 if (MapInfo_Get_ByID(i))
\r
1885 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
\r
1888 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
\r
1889 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1895 MapInfo_ClearTemps();
\r
1897 if (s == "" && page == 0)
\r
1898 return "No records are available on this server.\n";
\r
1903 string getrankings()
\r
1914 map = GetMapname();
\r
1916 for (i = 1; i <= RANKINGS_CNT; ++i)
\r
1918 t = race_GetTime(i);
\r
1921 n = race_GetName(i);
\r
1922 p = race_PlaceName(i);
\r
1923 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
\r
1926 MapInfo_ClearTemps();
\r
1929 return strcat("No records are available for the map: ", map, "\n");
\r
1931 return strcat("Records for ", map, ":\n", s);
\r
1934 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
\r
1937 vector start, org, delta, end, enddown, mstart;
\r
1939 m = e.dphitcontentsmask;
\r
1940 e.dphitcontentsmask = goodcontents | badcontents;
\r
1943 delta = world.maxs - world.mins;
\r
1945 for (i = 0; i < attempts; ++i)
\r
1947 start_x = org_x + random() * delta_x;
\r
1948 start_y = org_y + random() * delta_y;
\r
1949 start_z = org_z + random() * delta_z;
\r
1951 // rule 1: start inside world bounds, and outside
\r
1952 // solid, and don't start from somewhere where you can
\r
1953 // fall down to evil
\r
1954 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1955 if (trace_fraction >= 1)
\r
1957 if (trace_startsolid)
\r
1959 if (trace_dphitcontents & badcontents)
\r
1961 if (trace_dphitq3surfaceflags & badsurfaceflags)
\r
1964 // rule 2: if we are too high, lower the point
\r
1965 if (trace_fraction * delta_z > maxaboveground)
\r
1966 start = trace_endpos + '0 0 1' * maxaboveground;
\r
1967 enddown = trace_endpos;
\r
1969 // rule 3: make sure we aren't outside the map. This only works
\r
1970 // for somewhat well formed maps. A good rule of thumb is that
\r
1971 // the map should have a convex outside hull.
\r
1972 // these can be traceLINES as we already verified the starting box
\r
1973 mstart = start + 0.5 * (e.mins + e.maxs);
\r
1974 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1975 if (trace_fraction >= 1)
\r
1977 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1978 if (trace_fraction >= 1)
\r
1980 traceline(mstart, mstart + '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1981 if (trace_fraction >= 1)
\r
1983 traceline(mstart, mstart - '0 1 0' * delta_y, MOVE_NORMAL, e);
\r
1984 if (trace_fraction >= 1)
\r
1986 traceline(mstart, mstart + '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1987 if (trace_fraction >= 1)
\r
1990 // find a random vector to "look at"
\r
1991 end_x = org_x + random() * delta_x;
\r
1992 end_y = org_y + random() * delta_y;
\r
1993 end_z = org_z + random() * delta_z;
\r
1994 end = start + normalize(end - start) * vlen(delta);
\r
1996 // rule 4: start TO end must not be too short
\r
1997 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
\r
1998 if (trace_startsolid)
\r
2000 if (trace_fraction < minviewdistance / vlen(delta))
\r
2003 // rule 5: don't want to look at sky
\r
2004 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
2007 // rule 6: we must not end up in trigger_hurt
\r
2008 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
\r
2010 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
\r
2017 e.dphitcontentsmask = m;
\r
2021 setorigin(e, start);
\r
2022 e.angles = vectoangles(end - start);
\r
2023 dprint("Needed ", ftos(i + 1), " attempts\n");
\r
2030 float zcurveparticles_effectno;
\r
2031 vector zcurveparticles_start;
\r
2032 float zcurveparticles_spd;
\r
2034 void endzcurveparticles()
\r
2036 if(zcurveparticles_effectno)
\r
2039 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
\r
2041 zcurveparticles_effectno = 0;
\r
2044 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
\r
2046 spd = bound(0, floor(spd / 16), 32767);
\r
2047 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
\r
2049 endzcurveparticles();
\r
2050 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
\r
2051 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
\r
2052 WriteShort(MSG_BROADCAST, effectno);
\r
2053 WriteCoord(MSG_BROADCAST, start_x);
\r
2054 WriteCoord(MSG_BROADCAST, start_y);
\r
2055 WriteCoord(MSG_BROADCAST, start_z);
\r
2056 zcurveparticles_effectno = effectno;
\r
2057 zcurveparticles_start = start;
\r
2060 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
\r
2061 WriteCoord(MSG_BROADCAST, end_x);
\r
2062 WriteCoord(MSG_BROADCAST, end_y);
\r
2063 WriteCoord(MSG_BROADCAST, end_z);
\r
2064 WriteCoord(MSG_BROADCAST, end_dz);
\r
2065 zcurveparticles_spd = spd;
\r
2068 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
\r
2071 vector vecxy, velxy;
\r
2073 vecxy = end - start;
\r
2078 if (vlen(velxy) < 0.000001 * fabs(vel_z))
\r
2080 endzcurveparticles();
\r
2081 trailparticles(world, effectno, start, end);
\r
2085 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
\r
2086 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
\r
2089 string GetGametype(); // g_world.qc
\r
2090 void write_recordmarker(entity pl, float tstart, float dt)
\r
2092 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
\r
2094 // also write a marker into demo files for demotc-race-record-extractor to find
\r
2097 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
\r
2098 " ", ftos(tstart), " ", ftos(dt), "\n"));
\r
2101 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
\r
2103 switch(self.owner.cvar_cl_gunalign)
\r
2114 if(allowcenter) // 2: allow center handedness
\r
2127 if(allowcenter) // 2: allow center handedness
\r
2143 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
\r
2148 if (cvar("g_shootfromeye"))
\r
2152 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2160 else if (cvar("g_shootfromcenter"))
\r
2164 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2172 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
\r
2182 else if (cvar("g_shootfromclient"))
\r
2184 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
\r
2191 void attach_sameorigin(entity e, entity to, string tag)
\r
2193 vector org, t_forward, t_left, t_up, e_forward, e_up;
\r
2194 vector org0, ang0;
\r
2200 org = e.origin - gettaginfo(to, gettagindex(to, tag));
\r
2201 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
\r
2202 t_forward = v_forward * tagscale;
\r
2203 t_left = v_right * -tagscale;
\r
2204 t_up = v_up * tagscale;
\r
2206 e.origin_x = org * t_forward;
\r
2207 e.origin_y = org * t_left;
\r
2208 e.origin_z = org * t_up;
\r
2210 // current forward and up directions
\r
2211 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2212 e.angles = AnglesTransform_FromVAngles(e.angles);
\r
2214 e.angles = AnglesTransform_FromAngles(e.angles);
\r
2215 fixedmakevectors(e.angles);
\r
2217 // untransform forward, up!
\r
2218 e_forward_x = v_forward * t_forward;
\r
2219 e_forward_y = v_forward * t_left;
\r
2220 e_forward_z = v_forward * t_up;
\r
2221 e_up_x = v_up * t_forward;
\r
2222 e_up_y = v_up * t_left;
\r
2223 e_up_z = v_up * t_up;
\r
2225 e.angles = fixedvectoangles2(e_forward, e_up);
\r
2226 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2227 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2229 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2231 setattachment(e, to, tag);
\r
2232 setorigin(e, e.origin);
\r
2235 void detach_sameorigin(entity e)
\r
2238 org = gettaginfo(e, 0);
\r
2239 e.angles = fixedvectoangles2(v_forward, v_up);
\r
2240 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2241 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2243 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2244 setorigin(e, org);
\r
2245 setattachment(e, world, "");
\r
2246 setorigin(e, e.origin);
\r
2249 void follow_sameorigin(entity e, entity to)
\r
2251 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
\r
2252 e.aiment = to; // make the hole follow bmodel
\r
2253 e.punchangle = to.angles; // the original angles of bmodel
\r
2254 e.view_ofs = e.origin - to.origin; // relative origin
\r
2255 e.v_angle = e.angles - to.angles; // relative angles
\r
2258 void unfollow_sameorigin(entity e)
\r
2260 e.movetype = MOVETYPE_NONE;
\r
2263 entity gettaginfo_relative_ent;
\r
2264 vector gettaginfo_relative(entity e, float tag)
\r
2266 if (!gettaginfo_relative_ent)
\r
2268 gettaginfo_relative_ent = spawn();
\r
2269 gettaginfo_relative_ent.effects = EF_NODRAW;
\r
2271 gettaginfo_relative_ent.model = e.model;
\r
2272 gettaginfo_relative_ent.modelindex = e.modelindex;
\r
2273 gettaginfo_relative_ent.frame = e.frame;
\r
2274 return gettaginfo(gettaginfo_relative_ent, tag);
\r
2277 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
\r
2281 if (pl.soundentity.cnt & p)
\r
2283 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
\r
2284 pl.soundentity.cnt |= p;
\r
2287 void SoundEntity_StopSound(entity pl, float chan)
\r
2291 if (pl.soundentity.cnt & p)
\r
2293 stopsoundto(MSG_ALL, pl.soundentity, chan);
\r
2294 pl.soundentity.cnt &~= p;
\r
2298 void SoundEntity_Attach(entity pl)
\r
2300 pl.soundentity = spawn();
\r
2301 pl.soundentity.classname = "soundentity";
\r
2302 pl.soundentity.owner = pl;
\r
2303 setattachment(pl.soundentity, pl, "");
\r
2304 setmodel(pl.soundentity, "null");
\r
2307 void SoundEntity_Detach(entity pl)
\r
2310 for (i = 0; i <= 7; ++i)
\r
2311 SoundEntity_StopSound(pl, i);
\r
2315 float ParseCommandPlayerSlotTarget_firsttoken;
\r
2316 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
\r
2324 ParseCommandPlayerSlotTarget_firsttoken = -1;
\r
2328 if (substring(argv(idx), 0, 1) == "#")
\r
2330 s = substring(argv(idx), 1, -1);
\r
2338 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2339 if (s == ftos(stof(s)))
\r
2341 e = edict_num(stof(s));
\r
2342 if (e.flags & FL_CLIENT)
\r
2348 // it must be a nick name
\r
2351 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2354 FOR_EACH_CLIENT(head)
\r
2355 if (head.netname == s)
\r
2363 s = strdecolorize(s);
\r
2365 FOR_EACH_CLIENT(head)
\r
2366 if (strdecolorize(head.netname) == s)
\r
2381 float modeleffect_SendEntity(entity to, float sf)
\r
2384 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
\r
2387 if(self.velocity != '0 0 0')
\r
2389 if(self.angles != '0 0 0')
\r
2391 if(self.avelocity != '0 0 0')
\r
2394 WriteByte(MSG_ENTITY, f);
\r
2395 WriteShort(MSG_ENTITY, self.modelindex);
\r
2396 WriteByte(MSG_ENTITY, self.skin);
\r
2397 WriteByte(MSG_ENTITY, self.frame);
\r
2398 WriteCoord(MSG_ENTITY, self.origin_x);
\r
2399 WriteCoord(MSG_ENTITY, self.origin_y);
\r
2400 WriteCoord(MSG_ENTITY, self.origin_z);
\r
2403 WriteCoord(MSG_ENTITY, self.velocity_x);
\r
2404 WriteCoord(MSG_ENTITY, self.velocity_y);
\r
2405 WriteCoord(MSG_ENTITY, self.velocity_z);
\r
2409 WriteCoord(MSG_ENTITY, self.angles_x);
\r
2410 WriteCoord(MSG_ENTITY, self.angles_y);
\r
2411 WriteCoord(MSG_ENTITY, self.angles_z);
\r
2415 WriteCoord(MSG_ENTITY, self.avelocity_x);
\r
2416 WriteCoord(MSG_ENTITY, self.avelocity_y);
\r
2417 WriteCoord(MSG_ENTITY, self.avelocity_z);
\r
2419 WriteShort(MSG_ENTITY, self.scale * 256.0);
\r
2420 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
\r
2421 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
\r
2422 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
\r
2423 WriteByte(MSG_ENTITY, self.alpha * 255.0);
\r
2428 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
2433 e.classname = "modeleffect";
\r
2439 e.avelocity = angv;
\r
2441 e.teleport_time = t1;
\r
2445 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2449 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2452 sz = max(e.scale, e.scale2);
\r
2453 setsize(e, e.mins * sz, e.maxs * sz);
\r
2454 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
\r
2457 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
\r
2459 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
\r
2462 float randombit(float bits)
\r
2464 if not(bits & (bits-1)) // this ONLY holds for powers of two!
\r
2473 for(f = 1; f <= bits; f *= 2)
\r
2482 r = (r - 1) / (n - 1);
\r
2489 float randombits(float bits, float k, float error_return)
\r
2493 while(k > 0 && bits != r)
\r
2495 r += randombit(bits - r);
\r
2504 void randombit_test(float bits, float iter)
\r
2508 print(ftos(randombit(bits)), "\n");
\r
2513 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
\r
2515 if(halflifedist > 0)
\r
2516 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
\r
2517 else if(halflifedist < 0)
\r
2518 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
\r
2527 #define cvar_string_normal cvar_string_builtin
\r
2528 #define cvar_normal cvar_builtin
\r
2530 string cvar_string_normal(string n)
\r
2532 if not(cvar_type(n) & 1)
\r
2533 backtrace(strcat("Attempt to access undefined cvar: ", n));
\r
2534 return cvar_string_builtin(n);
\r
2537 float cvar_normal(string n)
\r
2539 return stof(cvar_string_normal(n));
\r
2542 #define cvar_set_normal cvar_set_builtin
\r
2544 void defer_think()
\r
2549 self = self.owner;
\r
2550 oself.think = SUB_Remove;
\r
2551 oself.nextthink = time;
\r
2557 Execute func() after time + fdelay.
\r
2558 self when func is executed = self when defer is called
\r
2560 void defer(float fdelay, void() func)
\r
2567 e.think = defer_think;
\r
2568 e.nextthink = time + fdelay;
\r