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_autodigest, "cl_vore_autodigest");
\r
623 self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
\r
624 self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
\r
626 #ifdef ALLOW_FORCEMODELS
\r
627 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
\r
628 GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromvoretournament, "cl_forceplayermodelsfromvoretournament");
\r
630 GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
\r
632 // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
\r
635 if (s == "cl_weaponpriority")
\r
636 self.switchweapon = w_getbestweapon(self);
\r
640 float fexists(string f)
\r
643 fh = fopen(f, FILE_READ);
\r
650 void backtrace(string msg)
\r
653 dev = cvar("developer");
\r
654 war = cvar("prvm_backtraceforwarnings");
\r
655 cvar_set("developer", "1");
\r
656 cvar_set("prvm_backtraceforwarnings", "1");
\r
658 print("--- CUT HERE ---\nWARNING: ");
\r
661 remove(world); // isn't there any better way to cause a backtrace?
\r
662 print("\n--- CUT UNTIL HERE ---\n");
\r
663 cvar_set("developer", ftos(dev));
\r
664 cvar_set("prvm_backtraceforwarnings", ftos(war));
\r
667 string Team_ColorCode(float teamid)
\r
669 if (teamid == COLOR_TEAM1)
\r
671 else if (teamid == COLOR_TEAM2)
\r
673 else if (teamid == COLOR_TEAM3)
\r
675 else if (teamid == COLOR_TEAM4)
\r
681 string Team_ColorName(float t)
\r
683 // fixme: Search for team entities and get their .netname's!
\r
684 if (t == COLOR_TEAM1)
\r
686 if (t == COLOR_TEAM2)
\r
688 if (t == COLOR_TEAM3)
\r
690 if (t == COLOR_TEAM4)
\r
695 string Team_ColorNameLowerCase(float t)
\r
697 // fixme: Search for team entities and get their .netname's!
\r
698 if (t == COLOR_TEAM1)
\r
700 if (t == COLOR_TEAM2)
\r
702 if (t == COLOR_TEAM3)
\r
704 if (t == COLOR_TEAM4)
\r
709 float ColourToNumber(string team_colour)
\r
711 if (team_colour == "red")
\r
712 return COLOR_TEAM1;
\r
714 if (team_colour == "blue")
\r
715 return COLOR_TEAM2;
\r
717 if (team_colour == "yellow")
\r
718 return COLOR_TEAM3;
\r
720 if (team_colour == "pink")
\r
721 return COLOR_TEAM4;
\r
723 if (team_colour == "auto")
\r
729 float NumberToTeamNumber(float number)
\r
732 return COLOR_TEAM1;
\r
735 return COLOR_TEAM2;
\r
738 return COLOR_TEAM3;
\r
741 return COLOR_TEAM4;
\r
746 #define CENTERPRIO_POINT 1
\r
747 #define CENTERPRIO_SPAM 2
\r
748 #define CENTERPRIO_VOTE 4
\r
749 #define CENTERPRIO_NORMAL 5
\r
750 #define CENTERPRIO_SHIELDING 7
\r
751 #define CENTERPRIO_MAPVOTE 9
\r
752 #define CENTERPRIO_IDLEKICK 50
\r
753 #define CENTERPRIO_ADMIN 99
\r
754 .float centerprint_priority;
\r
755 .float centerprint_expires;
\r
756 void centerprint_atprio(entity e, float prio, string s)
\r
758 if (intermission_running)
\r
759 if (prio < CENTERPRIO_MAPVOTE)
\r
761 if (time > e.centerprint_expires)
\r
762 e.centerprint_priority = 0;
\r
763 if (prio >= e.centerprint_priority)
\r
765 e.centerprint_priority = prio;
\r
766 if (timeoutStatus == 2)
\r
767 e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
\r
769 e.centerprint_expires = time + e.cvar_scr_centertime;
\r
770 centerprint_builtin(e, s);
\r
773 void centerprint_expire(entity e, float prio)
\r
775 if (prio == e.centerprint_priority)
\r
777 e.centerprint_priority = 0;
\r
778 centerprint_builtin(e, "");
\r
781 void centerprint(entity e, string s)
\r
783 centerprint_atprio(e, CENTERPRIO_NORMAL, s);
\r
786 // decolorizes and team colors the player name when needed
\r
787 string playername(entity p)
\r
790 if (teams_matter && !intermission_running && p.classname == "player")
\r
792 t = Team_ColorCode(p.team);
\r
793 return strcat(t, strdecolorize(p.netname));
\r
799 vector randompos(vector m1, vector m2)
\r
803 v_x = m2_x * random() + m1_x;
\r
804 v_y = m2_y * random() + m1_y;
\r
805 v_z = m2_z * random() + m1_z;
\r
809 float g_pickup_fuel;
\r
810 float g_pickup_fuel_jetpack;
\r
811 float g_pickup_fuel_max;
\r
812 float g_pickup_armorsmall;
\r
813 float g_pickup_armorsmall_max;
\r
814 float g_pickup_armormedium;
\r
815 float g_pickup_armormedium_max;
\r
816 float g_pickup_armorbig;
\r
817 float g_pickup_armorbig_max;
\r
818 float g_pickup_armorlarge;
\r
819 float g_pickup_armorlarge_max;
\r
820 float g_pickup_healthsmall;
\r
821 float g_pickup_healthsmall_max;
\r
822 float g_pickup_healthmedium;
\r
823 float g_pickup_healthmedium_max;
\r
824 float g_pickup_healthlarge;
\r
825 float g_pickup_healthlarge_max;
\r
826 float g_pickup_healthmega;
\r
827 float g_pickup_healthmega_max;
\r
828 float g_weaponspeedfactor;
\r
829 float g_weaponratefactor;
\r
830 float g_weapondamagefactor;
\r
831 float g_weaponforcefactor;
\r
832 float g_weaponspreadfactor;
\r
834 float start_weapons;
\r
836 float start_ammo_fuel;
\r
837 float start_health;
\r
838 float start_armorvalue;
\r
839 float warmup_start_weapons;
\r
840 float warmup_start_ammo_fuel;
\r
841 float warmup_start_health;
\r
842 float warmup_start_armorvalue;
\r
843 float g_weapon_stay;
\r
844 float g_ghost_items;
\r
846 entity get_weaponinfo(float w);
\r
848 float want_weapon(string cvarprefix, entity weaponinfo, float allguns)
\r
850 var float i = weaponinfo.weapon;
\r
855 var float t = cvar(strcat(cvarprefix, weaponinfo.netname));
\r
857 if (t < 0) // "default" weapon selection
\r
859 if(g_rpg) // no start weapons in RPG by default
\r
862 t = (i == WEP_GRABBER);
\r
868 void readplayerstartcvars()
\r
873 // initialize starting values for players
\r
876 start_health = cvar("g_balance_health_start");
\r
877 start_armorvalue = cvar("g_balance_armor_start");
\r
881 start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
\r
882 start_health = cvar("g_lms_start_health");
\r
883 start_armorvalue = cvar("g_lms_start_armor");
\r
885 else if (cvar("g_use_ammunition"))
\r
887 start_ammo_fuel = cvar("g_start_ammo_fuel");
\r
891 start_ammo_fuel = cvar("g_pickup_fuel_max");
\r
892 start_items |= IT_UNLIMITED_AMMO;
\r
895 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
897 e = get_weaponinfo(i);
\r
898 if(want_weapon("g_start_weapon_", e, FALSE))
\r
900 start_weapons |= e.weapons;
\r
901 weapon_action(e.weapon, WR_PRECACHE);
\r
907 warmup_start_ammo_fuel = start_ammo_fuel;
\r
908 warmup_start_health = start_health;
\r
909 warmup_start_armorvalue = start_armorvalue;
\r
910 warmup_start_weapons = start_weapons;
\r
912 if (cvar("g_use_ammunition"))
\r
914 warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
\r
916 warmup_start_health = cvar("g_warmup_start_health");
\r
917 warmup_start_armorvalue = cvar("g_warmup_start_armor");
\r
918 warmup_start_weapons = 0;
\r
919 for (i = WEP_FIRST; i <= WEP_LAST; ++i)
\r
921 e = get_weaponinfo(i);
\r
922 if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")))
\r
924 warmup_start_weapons |= e.weapons;
\r
925 weapon_action(e.weapon, WR_PRECACHE);
\r
932 start_items |= IT_FUEL_REGEN;
\r
933 start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
934 warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
\r
938 start_items |= IT_JETPACK;
\r
940 if (g_weapon_stay == 2)
\r
942 if (!start_ammo_fuel) start_ammo_fuel = g_pickup_fuel;
\r
943 if (!warmup_start_ammo_fuel) warmup_start_ammo_fuel = g_pickup_fuel;
\r
946 start_ammo_fuel = max(0, start_ammo_fuel);
\r
948 warmup_start_ammo_fuel = max(0, warmup_start_ammo_fuel);
\r
952 float g_bugrigs_planar_movement;
\r
953 float g_bugrigs_planar_movement_car_jumping;
\r
954 float g_bugrigs_reverse_spinning;
\r
955 float g_bugrigs_reverse_speeding;
\r
956 float g_bugrigs_reverse_stopping;
\r
957 float g_bugrigs_air_steering;
\r
958 float g_bugrigs_angle_smoothing;
\r
959 float g_bugrigs_friction_floor;
\r
960 float g_bugrigs_friction_brake;
\r
961 float g_bugrigs_friction_air;
\r
962 float g_bugrigs_accel;
\r
963 float g_bugrigs_speed_ref;
\r
964 float g_bugrigs_speed_pow;
\r
965 float g_bugrigs_steer;
\r
967 float g_touchexplode;
\r
968 float g_touchexplode_radius;
\r
969 float g_touchexplode_damage;
\r
970 float g_touchexplode_edgedamage;
\r
971 float g_touchexplode_force;
\r
973 float sv_autotaunt;
\r
976 float sv_pitch_min;
\r
977 float sv_pitch_max;
\r
978 float sv_pitch_fixyaw;
\r
980 float sv_accuracy_data_share;
\r
982 void readlevelcvars(void)
\r
984 g_bugrigs = cvar("g_bugrigs");
\r
985 g_bugrigs_planar_movement = cvar("g_bugrigs_planar_movement");
\r
986 g_bugrigs_planar_movement_car_jumping = cvar("g_bugrigs_planar_movement_car_jumping");
\r
987 g_bugrigs_reverse_spinning = cvar("g_bugrigs_reverse_spinning");
\r
988 g_bugrigs_reverse_speeding = cvar("g_bugrigs_reverse_speeding");
\r
989 g_bugrigs_reverse_stopping = cvar("g_bugrigs_reverse_stopping");
\r
990 g_bugrigs_air_steering = cvar("g_bugrigs_air_steering");
\r
991 g_bugrigs_angle_smoothing = cvar("g_bugrigs_angle_smoothing");
\r
992 g_bugrigs_friction_floor = cvar("g_bugrigs_friction_floor");
\r
993 g_bugrigs_friction_brake = cvar("g_bugrigs_friction_brake");
\r
994 g_bugrigs_friction_air = cvar("g_bugrigs_friction_air");
\r
995 g_bugrigs_accel = cvar("g_bugrigs_accel");
\r
996 g_bugrigs_speed_ref = cvar("g_bugrigs_speed_ref");
\r
997 g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
\r
998 g_bugrigs_steer = cvar("g_bugrigs_steer");
\r
1000 g_touchexplode = cvar("g_touchexplode");
\r
1001 g_touchexplode_radius = cvar("g_touchexplode_radius");
\r
1002 g_touchexplode_damage = cvar("g_touchexplode_damage");
\r
1003 g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
\r
1004 g_touchexplode_force = cvar("g_touchexplode_force");
\r
1006 #ifdef ALLOW_FORCEMODELS
\r
1007 sv_clforceplayermodels = cvar("sv_clforceplayermodels");
\r
1010 sv_clones = cvar("sv_clones");
\r
1011 sv_gentle = cvar("sv_gentle");
\r
1012 sv_foginterval = cvar("sv_foginterval");
\r
1013 g_cloaked = cvar("g_cloaked");
\r
1014 g_jump_grunt = cvar("g_jump_grunt");
\r
1015 g_footsteps = cvar("g_footsteps");
\r
1016 g_jetpack = cvar("g_jetpack");
\r
1017 g_midair = cvar("g_midair");
\r
1018 g_norecoil = cvar("g_norecoil");
\r
1019 g_vampire = cvar("g_vampire");
\r
1020 g_bloodloss = cvar("g_bloodloss");
\r
1021 sv_maxidle = cvar("sv_maxidle");
\r
1022 sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle");
\r
1023 sv_pogostick = cvar("sv_pogostick");
\r
1024 sv_doublejump = cvar("sv_doublejump");
\r
1025 g_ctf_reverse = cvar("g_ctf_reverse");
\r
1026 sv_autotaunt = cvar("sv_autotaunt");
\r
1027 sv_taunt = cvar("sv_taunt");
\r
1029 inWarmupStage = cvar("g_warmup");
\r
1030 g_warmup_limit = cvar("g_warmup_limit");
\r
1031 g_warmup_allguns = cvar("g_warmup_allguns");
\r
1032 g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
\r
1034 if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
\r
1035 inWarmupStage = 0; // these modes cannot work together, sorry
\r
1037 g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
\r
1038 g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
\r
1039 g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
\r
1040 g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
\r
1041 g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
\r
1042 g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
\r
1043 g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
\r
1044 g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
\r
1045 g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
\r
1046 g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
\r
1047 g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
\r
1048 g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
\r
1050 g_weaponspeedfactor = cvar("g_weaponspeedfactor");
\r
1051 g_weaponratefactor = cvar("g_weaponratefactor");
\r
1052 g_weapondamagefactor = cvar("g_weapondamagefactor");
\r
1053 g_weaponforcefactor = cvar("g_weaponforcefactor");
\r
1054 g_weaponspreadfactor = cvar("g_weaponspreadfactor");
\r
1056 g_pickup_fuel = cvar("g_pickup_fuel");
\r
1057 g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
\r
1058 g_pickup_fuel_max = cvar("g_pickup_fuel_max");
\r
1059 g_pickup_armorsmall = cvar("g_pickup_armorsmall");
\r
1060 g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
\r
1061 g_pickup_armormedium = cvar("g_pickup_armormedium");
\r
1062 g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
\r
1063 g_pickup_armorbig = cvar("g_pickup_armorbig");
\r
1064 g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
\r
1065 g_pickup_armorlarge = cvar("g_pickup_armorlarge");
\r
1066 g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max");
\r
1067 g_pickup_healthsmall = cvar("g_pickup_healthsmall");
\r
1068 g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
\r
1069 g_pickup_healthmedium = cvar("g_pickup_healthmedium");
\r
1070 g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
\r
1071 g_pickup_healthlarge = cvar("g_pickup_healthlarge");
\r
1072 g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max");
\r
1073 g_pickup_healthmega = cvar("g_pickup_healthmega");
\r
1074 g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
\r
1076 g_weapon_stay = cvar("g_weapon_stay");
\r
1078 if (!g_weapon_stay && (cvar("deathmatch") == 2))
\r
1079 g_weapon_stay = 1;
\r
1081 g_ghost_items = cvar("g_ghost_items");
\r
1083 if(g_ghost_items >= 1)
\r
1084 g_ghost_items = 0.25; // default alpha value
\r
1086 if not(inWarmupStage && !g_ca)
\r
1087 game_starttime = cvar("g_start_delay");
\r
1089 sv_pitch_min = cvar("sv_pitch_min");
\r
1090 sv_pitch_max = cvar("sv_pitch_max");
\r
1091 sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
\r
1093 sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share"));
\r
1095 readplayerstartcvars();
\r
1099 // TODO sound pack system
\r
1102 string precache_sound_builtin (string s) = #19;
\r
1103 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1104 string precache_sound(string s)
\r
1106 return precache_sound_builtin(strcat(soundpack, s));
\r
1108 void play2(entity e, string filename)
\r
1110 stuffcmd(e, strcat("play2 ", soundpack, filename, "\n"));
\r
1112 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1114 sound_builtin(e, chan, strcat(soundpack, samp), vol, atten);
\r
1118 // Sound functions
\r
1119 string precache_sound (string s) = #19;
\r
1120 void(entity e, float chan, string samp, float vol, float atten) sound_builtin = #8;
\r
1121 float precache_sound_index (string s) = #19;
\r
1123 #define SND_VOLUME 1
\r
1124 #define SND_ATTENUATION 2
\r
1125 #define SND_LARGEENTITY 8
\r
1126 #define SND_LARGESOUND 16
\r
1128 float sound_allowed(float dest, entity e)
\r
1130 // sounds from world may always pass
\r
1133 if (e.classname == "body")
\r
1135 if (e.owner && e.owner != e)
\r
1140 // sounds to self may always pass
\r
1141 if (dest == MSG_ONE)
\r
1142 if (e == msg_entity)
\r
1144 // sounds by players can be removed
\r
1145 if (cvar("bot_sound_monopoly"))
\r
1146 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1148 // anything else may pass
\r
1152 void sound(entity e, float chan, string samp, float vol, float atten)
\r
1154 if (!sound_allowed(MSG_BROADCAST, e))
\r
1156 sound_builtin(e, chan, samp, vol, atten);
\r
1158 void soundtoat(float dest, entity e, vector o, float chan, string samp, float vol, float atten)
\r
1162 if (!sound_allowed(dest, e))
\r
1165 entno = num_for_edict(e);
\r
1166 idx = precache_sound_index(samp);
\r
1171 atten = floor(atten * 64);
\r
1172 vol = floor(vol * 255);
\r
1175 sflags |= SND_VOLUME;
\r
1177 sflags |= SND_ATTENUATION;
\r
1178 if (entno >= 8192)
\r
1179 sflags |= SND_LARGEENTITY;
\r
1181 sflags |= SND_LARGESOUND;
\r
1183 WriteByte(dest, SVC_SOUND);
\r
1184 WriteByte(dest, sflags);
\r
1185 if (sflags & SND_VOLUME)
\r
1186 WriteByte(dest, vol);
\r
1187 if (sflags & SND_ATTENUATION)
\r
1188 WriteByte(dest, atten);
\r
1189 if (sflags & SND_LARGEENTITY)
\r
1191 WriteShort(dest, entno);
\r
1192 WriteByte(dest, chan);
\r
1196 WriteShort(dest, entno * 8 + chan);
\r
1198 if (sflags & SND_LARGESOUND)
\r
1199 WriteShort(dest, idx);
\r
1201 WriteByte(dest, idx);
\r
1203 WriteCoord(dest, o_x);
\r
1204 WriteCoord(dest, o_y);
\r
1205 WriteCoord(dest, o_z);
\r
1207 void soundto(float dest, entity e, float chan, string samp, float vol, float atten)
\r
1211 if (!sound_allowed(dest, e))
\r
1214 o = e.origin + 0.5 * (e.mins + e.maxs);
\r
1215 soundtoat(dest, e, o, chan, samp, vol, atten);
\r
1217 void soundat(entity e, vector o, float chan, string samp, float vol, float atten)
\r
1219 soundtoat(MSG_BROADCAST, e, o, chan, samp, vol, atten);
\r
1221 void stopsoundto(float dest, entity e, float chan)
\r
1225 if (!sound_allowed(dest, e))
\r
1228 entno = num_for_edict(e);
\r
1230 if (entno >= 8192)
\r
1232 float idx, sflags;
\r
1233 idx = precache_sound_index("misc/null.wav");
\r
1234 sflags = SND_LARGEENTITY;
\r
1236 sflags |= SND_LARGESOUND;
\r
1237 WriteByte(dest, SVC_SOUND);
\r
1238 WriteByte(dest, sflags);
\r
1239 WriteShort(dest, entno);
\r
1240 WriteByte(dest, chan);
\r
1241 if (sflags & SND_LARGESOUND)
\r
1242 WriteShort(dest, idx);
\r
1244 WriteByte(dest, idx);
\r
1245 WriteCoord(dest, e.origin_x);
\r
1246 WriteCoord(dest, e.origin_y);
\r
1247 WriteCoord(dest, e.origin_z);
\r
1251 WriteByte(dest, SVC_STOPSOUND);
\r
1252 WriteShort(dest, entno * 8 + chan);
\r
1255 void stopsound(entity e, float chan)
\r
1257 if (!sound_allowed(MSG_BROADCAST, e))
\r
1260 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
\r
1261 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
\r
1264 void play2(entity e, string filename)
\r
1266 //stuffcmd(e, strcat("play2 ", filename, "\n"));
\r
1267 if (clienttype(e) == CLIENTTYPE_REAL)
\r
1270 soundtoat(MSG_ONE, world, '0 0 0', CHAN_AUTO, filename, VOL_BASE, ATTN_NONE);
\r
1274 // use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame)
\r
1276 float spamsound(entity e, float chan, string samp, float vol, float atten)
\r
1278 if (!sound_allowed(MSG_BROADCAST, e))
\r
1281 if (time > e.spamtime)
\r
1283 e.spamtime = time;
\r
1284 sound(e, chan, samp, vol, atten);
\r
1290 void play2team(float t, string filename)
\r
1292 local entity head;
\r
1294 if (cvar("bot_sound_monopoly"))
\r
1297 FOR_EACH_REALPLAYER(head)
\r
1299 if (head.team == t)
\r
1300 play2(head, filename);
\r
1304 void play2all(string samp)
\r
1306 if (cvar("bot_sound_monopoly"))
\r
1309 sound(world, CHAN_AUTO, samp, VOL_BASE, ATTN_NONE);
\r
1312 void PrecachePlayerSounds(string f);
\r
1313 void precache_all_models(string pattern)
\r
1315 float globhandle, i, n;
\r
1318 globhandle = search_begin(pattern, TRUE, FALSE);
\r
1319 if (globhandle < 0)
\r
1321 n = search_getsize(globhandle);
\r
1322 for (i = 0; i < n; ++i)
\r
1324 //print(search_getfilename(globhandle, i), "\n");
\r
1325 f = search_getfilename(globhandle, i);
\r
1326 precache_model(f);
\r
1327 PrecachePlayerSounds(strcat(f, ".sounds"));
\r
1329 search_end(globhandle);
\r
1334 // gamemode related things
\r
1335 precache_model ("models/misc/chatbubble.spr");
\r
1336 precache_model ("models/misc/teambubble.spr");
\r
1337 precache_model ("models/misc/teambubbleheal.spr");
\r
1339 // used by the waypoint editor
\r
1340 precache_model ("models/rune.mdl");
\r
1342 #ifdef TTURRETS_ENABLED
\r
1343 if (cvar("g_turrets"))
\r
1344 turrets_precash();
\r
1347 // Precache all player models if desired
\r
1348 if (cvar("sv_precacheplayermodels"))
\r
1350 PrecachePlayerSounds("sound/player/default.sounds");
\r
1351 precache_all_models("models/player/*.zym");
\r
1352 precache_all_models("models/player/*.dpm");
\r
1353 precache_all_models("models/player/*.md3");
\r
1354 precache_all_models("models/player/*.psk");
\r
1355 //precache_model("models/player/vixen.zym");
\r
1358 if (cvar("sv_defaultcharacter"))
\r
1361 s = cvar_string("sv_defaultplayermodel_red");
\r
1364 precache_model(s);
\r
1365 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1367 s = cvar_string("sv_defaultplayermodel_blue");
\r
1370 precache_model(s);
\r
1371 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1373 s = cvar_string("sv_defaultplayermodel_yellow");
\r
1376 precache_model(s);
\r
1377 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1379 s = cvar_string("sv_defaultplayermodel_pink");
\r
1382 precache_model(s);
\r
1383 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1385 s = cvar_string("sv_defaultplayermodel");
\r
1388 precache_model(s);
\r
1389 PrecachePlayerSounds(strcat(s, ".sounds"));
\r
1395 PrecacheGlobalSound((globalsound_step = "misc/footstep0 6"));
\r
1396 PrecacheGlobalSound((globalsound_metalstep = "misc/metalfootstep0 6"));
\r
1399 // gore and miscellaneous sounds
\r
1400 //precache_sound ("misc/h2ohit.wav");
\r
1401 precache_model ("models/grabber.md3");
\r
1402 precache_sound ("misc/armorimpact.wav");
\r
1403 precache_sound ("misc/bodyimpact1.wav");
\r
1404 precache_sound ("misc/bodyimpact2.wav");
\r
1405 precache_sound ("misc/gib.wav");
\r
1406 precache_sound ("misc/gib_splat01.wav");
\r
1407 precache_sound ("misc/gib_splat02.wav");
\r
1408 precache_sound ("misc/gib_splat03.wav");
\r
1409 precache_sound ("misc/gib_splat04.wav");
\r
1410 precache_sound ("misc/hit.wav");
\r
1411 precache_sound ("misc/typehit.wav");
\r
1412 precache_sound ("misc/unavailable.wav");
\r
1413 PrecacheGlobalSound((globalsound_fall = "misc/hitground 4"));
\r
1414 PrecacheGlobalSound((globalsound_metalfall = "misc/metalhitground 4"));
\r
1415 precache_sound ("misc/null.wav");
\r
1416 precache_sound ("misc/spawn.wav");
\r
1417 precache_sound ("misc/talk.wav");
\r
1418 precache_sound ("misc/teleport.wav");
\r
1419 precache_sound ("misc/poweroff.wav");
\r
1420 precache_sound ("player/lava.wav");
\r
1421 precache_sound ("player/slime.wav");
\r
1422 precache_sound ("player/digest.wav");
\r
1423 precache_sound ("misc/health_regen.ogg");
\r
1424 precache_sound ("misc/armor_regen.ogg");
\r
1427 precache_sound ("misc/jetpack_fly.wav");
\r
1429 precache_model ("models/sprites/0.spr32");
\r
1430 precache_model ("models/sprites/1.spr32");
\r
1431 precache_model ("models/sprites/2.spr32");
\r
1432 precache_model ("models/sprites/3.spr32");
\r
1433 precache_model ("models/sprites/4.spr32");
\r
1434 precache_model ("models/sprites/5.spr32");
\r
1435 precache_model ("models/sprites/6.spr32");
\r
1436 precache_model ("models/sprites/7.spr32");
\r
1437 precache_model ("models/sprites/8.spr32");
\r
1438 precache_model ("models/sprites/9.spr32");
\r
1439 precache_model ("models/sprites/10.spr32");
\r
1441 // common weapon precaches
\r
1442 precache_sound ("weapons/weapon_switch.wav");
\r
1443 precache_sound ("weapons/weaponpickup.wav");
\r
1444 precache_sound ("weapons/grabber_fire.wav"); // grabber
\r
1445 precache_sound ("weapons/grabber_altfire.wav"); // grabber
\r
1446 precache_sound ("weapons/grabber_impact.wav"); // grabber
\r
1447 precache_sound ("weapons/stomachkick.ogg");
\r
1449 if (cvar("sv_precacheweapons"))
\r
1451 //precache weapon models/sounds
\r
1454 while (wep <= WEP_LAST)
\r
1456 weapon_action(wep, WR_PRECACHE);
\r
1461 precache_model("models/elaser.mdl");
\r
1462 precache_model("models/laser.mdl");
\r
1463 precache_model("models/ebomb.mdl");
\r
1466 // Disabled this code because it simply does not work (e.g. ignores bgmvolume, overlaps with "cd loop" controlled tracks).
\r
1468 if (!self.noise && self.music) // quake 3 uses the music field
\r
1469 self.noise = self.music;
\r
1471 // plays music for the level if there is any
\r
1474 precache_sound (self.noise);
\r
1475 ambientsound ('0 0 0', self.noise, VOL_BASE, ATTN_NONE);
\r
1480 // sorry, but using \ in macros breaks line numbers
\r
1481 #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
1482 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
\r
1483 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
\r
1485 // WARNING: this kills the trace globals
\r
1486 #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
\r
1487 #define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
\r
1489 #define INITPRIO_FIRST 0
\r
1490 #define INITPRIO_GAMETYPE 0
\r
1491 #define INITPRIO_GAMETYPE_FALLBACK 1
\r
1492 #define INITPRIO_CVARS 5
\r
1493 #define INITPRIO_FINDTARGET 10
\r
1494 #define INITPRIO_DROPTOFLOOR 20
\r
1495 #define INITPRIO_SETLOCATION 90
\r
1496 #define INITPRIO_LINKDOORS 91
\r
1497 #define INITPRIO_LAST 99
\r
1499 .void(void) initialize_entity;
\r
1500 .float initialize_entity_order;
\r
1501 .entity initialize_entity_next;
\r
1502 entity initialize_entity_first;
\r
1504 void make_safe_for_remove(entity e)
\r
1506 if (e.initialize_entity)
\r
1509 for (ent = initialize_entity_first; ent; )
\r
1511 if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e)))
\r
1513 //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n");
\r
1514 // skip it in linked list
\r
1517 prev.initialize_entity_next = ent.initialize_entity_next;
\r
1518 ent = prev.initialize_entity_next;
\r
1522 initialize_entity_first = ent.initialize_entity_next;
\r
1523 ent = initialize_entity_first;
\r
1529 ent = ent.initialize_entity_next;
\r
1535 void objerror(string s)
\r
1537 make_safe_for_remove(self);
\r
1538 objerror_builtin(s);
\r
1541 void remove_unsafely(entity e)
\r
1543 remove_builtin(e);
\r
1546 void remove_safely(entity e)
\r
1548 make_safe_for_remove(e);
\r
1549 remove_builtin(e);
\r
1552 void InitializeEntity(entity e, void(void) func, float order)
\r
1556 if (!e || e.initialize_entity)
\r
1558 // make a proxy initializer entity
\r
1562 e.classname = "initialize_entity";
\r
1566 e.initialize_entity = func;
\r
1567 e.initialize_entity_order = order;
\r
1569 cur = initialize_entity_first;
\r
1572 if (!cur || cur.initialize_entity_order > order)
\r
1574 // insert between prev and cur
\r
1576 prev.initialize_entity_next = e;
\r
1578 initialize_entity_first = e;
\r
1579 e.initialize_entity_next = cur;
\r
1583 cur = cur.initialize_entity_next;
\r
1586 void InitializeEntitiesRun()
\r
1588 entity startoflist;
\r
1589 startoflist = initialize_entity_first;
\r
1590 initialize_entity_first = world;
\r
1591 for (self = startoflist; self; )
\r
1594 var void(void) func;
\r
1595 e = self.initialize_entity_next;
\r
1596 func = self.initialize_entity;
\r
1597 self.initialize_entity_order = 0;
\r
1598 self.initialize_entity = func_null;
\r
1599 self.initialize_entity_next = world;
\r
1600 if (self.classname == "initialize_entity")
\r
1603 e_old = self.enemy;
\r
1604 remove_builtin(self);
\r
1607 //dprint("Delayed initialization: ", self.classname, "\n");
\r
1613 .float uncustomizeentityforclient_set;
\r
1614 .void(void) uncustomizeentityforclient;
\r
1615 void(void) SUB_Nullpointer = #0;
\r
1616 void UncustomizeEntitiesRun()
\r
1620 for (self = world; (self = findfloat(self, uncustomizeentityforclient_set, 1)); )
\r
1621 self.uncustomizeentityforclient();
\r
1624 void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
\r
1626 e.customizeentityforclient = customizer;
\r
1627 e.uncustomizeentityforclient = uncustomizer;
\r
1628 e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer);
\r
1631 .float nottargeted;
\r
1632 #define IFTARGETED if(!self.nottargeted && self.targetname != "")
\r
1634 void() SUB_Remove;
\r
1635 void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc)
\r
1639 if (e.classname == "")
\r
1640 e.classname = "net_linked";
\r
1642 if (e.model == "" || self.modelindex == 0)
\r
1646 setmodel(e, "null");
\r
1647 setsize(e, mi, ma);
\r
1650 e.SendEntity = sendfunc;
\r
1651 e.SendFlags = 0xFFFFFF;
\r
1654 e.effects |= EF_NODEPTHTEST;
\r
1658 e.nextthink = time + dt;
\r
1659 e.think = SUB_Remove;
\r
1663 void adaptor_think2touch()
\r
1672 void adaptor_think2use()
\r
1677 activator = world;
\r
1684 // deferred dropping
\r
1685 void DropToFloor_Handler()
\r
1687 droptofloor_builtin();
\r
1688 self.dropped_origin = self.origin;
\r
1691 void droptofloor()
\r
1693 InitializeEntity(self, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
\r
1698 float trace_hits_box_a0, trace_hits_box_a1;
\r
1700 float trace_hits_box_1d(float end, float thmi, float thma)
\r
1704 // just check if x is in range
\r
1712 // do the trace with respect to x
\r
1713 // 0 -> end has to stay in thmi -> thma
\r
1714 trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
\r
1715 trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
\r
1716 if (trace_hits_box_a0 > trace_hits_box_a1)
\r
1722 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
\r
1727 // now it is a trace from 0 to end
\r
1729 trace_hits_box_a0 = 0;
\r
1730 trace_hits_box_a1 = 1;
\r
1732 if (!trace_hits_box_1d(end_x, thmi_x, thma_x))
\r
1734 if (!trace_hits_box_1d(end_y, thmi_y, thma_y))
\r
1736 if (!trace_hits_box_1d(end_z, thmi_z, thma_z))
\r
1742 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
\r
1744 return trace_hits_box(start, end, thmi - ma, thma - mi);
\r
1747 float SUB_NoImpactCheck()
\r
1749 // zero hitcontents = this is not the real impact, but either the
\r
1750 // mirror-impact of something hitting the projectile instead of the
\r
1751 // projectile hitting the something, or a touchareagrid one. Neither of
\r
1752 // these stop the projectile from moving, so...
\r
1753 if(trace_dphitcontents == 0)
\r
1755 dprint("A hit happened with zero hit contents... DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct.\n");
\r
1758 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1760 if (other == world && self.size != '0 0 0')
\r
1763 tic = self.velocity * sys_frametime;
\r
1764 tic = tic + normalize(tic) * vlen(self.maxs - self.mins);
\r
1765 traceline(self.origin - tic, self.origin + tic, MOVE_NORMAL, self);
\r
1766 if (trace_fraction >= 1)
\r
1768 dprint("Odd... did not hit...?\n");
\r
1770 else if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
\r
1772 dprint("Detected and prevented the sky-grapple bug.\n");
\r
1780 #define SUB_OwnerCheck() (other && (other == self.owner))
\r
1782 float WarpZone_Projectile_Touch_ImpactFilter_Callback()
\r
1784 if(SUB_OwnerCheck())
\r
1786 if(SUB_NoImpactCheck())
\r
1791 if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
\r
1792 UpdateCSQCProjectileNextFrame(self);
\r
1795 #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
\r
1797 float MAX_IPBAN_URIS = 16;
\r
1799 float URI_GET_DISCARD = 0;
\r
1800 float URI_GET_IPBAN = 1;
\r
1801 float URI_GET_IPBAN_END = 16;
\r
1803 void URI_Get_Callback(float id, float status, string data)
\r
1805 dprint("Received HTTP request data for id ", ftos(id), "; status is ", ftos(status), "\nData is:\n");
\r
1807 dprint("\nEnd of data.\n");
\r
1809 if (id == URI_GET_DISCARD)
\r
1813 else if (id >= URI_GET_IPBAN && id <= URI_GET_IPBAN_END)
\r
1815 // online ban list
\r
1816 OnlineBanList_URI_Get_Callback(id, status, data);
\r
1820 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
\r
1824 void print_to(entity e, string s)
\r
1827 sprint(e, strcat(s, "\n"));
\r
1832 string getrecords(float page) // 50 records per page
\r
1846 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1848 if (MapInfo_Get_ByID(i))
\r
1850 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
\r
1853 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
\r
1854 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
\r
1862 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1864 if (MapInfo_Get_ByID(i))
\r
1866 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "time")));
\r
1869 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, RACE_RECORD, "netname"));
\r
1870 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1878 for (i = page * 200; i < MapInfo_count && i < page * 200 + 200; ++i)
\r
1880 if (MapInfo_Get_ByID(i))
\r
1882 r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "time")));
\r
1885 h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, CTS_RECORD, "netname"));
\r
1886 s = strcat(s, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
\r
1892 MapInfo_ClearTemps();
\r
1894 if (s == "" && page == 0)
\r
1895 return "No records are available on this server.\n";
\r
1900 string getrankings()
\r
1911 map = GetMapname();
\r
1913 for (i = 1; i <= RANKINGS_CNT; ++i)
\r
1915 t = race_GetTime(i);
\r
1918 n = race_GetName(i);
\r
1919 p = race_PlaceName(i);
\r
1920 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
\r
1923 MapInfo_ClearTemps();
\r
1926 return strcat("No records are available for the map: ", map, "\n");
\r
1928 return strcat("Records for ", map, ":\n", s);
\r
1931 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
\r
1934 vector start, org, delta, end, enddown, mstart;
\r
1936 m = e.dphitcontentsmask;
\r
1937 e.dphitcontentsmask = goodcontents | badcontents;
\r
1940 delta = world.maxs - world.mins;
\r
1942 for (i = 0; i < attempts; ++i)
\r
1944 start_x = org_x + random() * delta_x;
\r
1945 start_y = org_y + random() * delta_y;
\r
1946 start_z = org_z + random() * delta_z;
\r
1948 // rule 1: start inside world bounds, and outside
\r
1949 // solid, and don't start from somewhere where you can
\r
1950 // fall down to evil
\r
1951 tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta_z, MOVE_NORMAL, e);
\r
1952 if (trace_fraction >= 1)
\r
1954 if (trace_startsolid)
\r
1956 if (trace_dphitcontents & badcontents)
\r
1958 if (trace_dphitq3surfaceflags & badsurfaceflags)
\r
1961 // rule 2: if we are too high, lower the point
\r
1962 if (trace_fraction * delta_z > maxaboveground)
\r
1963 start = trace_endpos + '0 0 1' * maxaboveground;
\r
1964 enddown = trace_endpos;
\r
1966 // rule 3: make sure we aren't outside the map. This only works
\r
1967 // for somewhat well formed maps. A good rule of thumb is that
\r
1968 // the map should have a convex outside hull.
\r
1969 // these can be traceLINES as we already verified the starting box
\r
1970 mstart = start + 0.5 * (e.mins + e.maxs);
\r
1971 traceline(mstart, mstart + '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1972 if (trace_fraction >= 1)
\r
1974 traceline(mstart, mstart - '1 0 0' * delta_x, MOVE_NORMAL, e);
\r
1975 if (trace_fraction >= 1)
\r
1977 traceline(mstart, mstart + '0 1 0' * delta_y, 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 0 1' * delta_z, MOVE_NORMAL, e);
\r
1984 if (trace_fraction >= 1)
\r
1987 // find a random vector to "look at"
\r
1988 end_x = org_x + random() * delta_x;
\r
1989 end_y = org_y + random() * delta_y;
\r
1990 end_z = org_z + random() * delta_z;
\r
1991 end = start + normalize(end - start) * vlen(delta);
\r
1993 // rule 4: start TO end must not be too short
\r
1994 tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
\r
1995 if (trace_startsolid)
\r
1997 if (trace_fraction < minviewdistance / vlen(delta))
\r
2000 // rule 5: don't want to look at sky
\r
2001 if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
\r
2004 // rule 6: we must not end up in trigger_hurt
\r
2005 if (tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
\r
2007 dprint("trigger_hurt! ouch! and nothing else could find it!\n");
\r
2014 e.dphitcontentsmask = m;
\r
2018 setorigin(e, start);
\r
2019 e.angles = vectoangles(end - start);
\r
2020 dprint("Needed ", ftos(i + 1), " attempts\n");
\r
2027 float zcurveparticles_effectno;
\r
2028 vector zcurveparticles_start;
\r
2029 float zcurveparticles_spd;
\r
2031 void endzcurveparticles()
\r
2033 if(zcurveparticles_effectno)
\r
2036 WriteShort(MSG_BROADCAST, zcurveparticles_spd | 0x8000);
\r
2038 zcurveparticles_effectno = 0;
\r
2041 void zcurveparticles(float effectno, vector start, vector end, float end_dz, float spd)
\r
2043 spd = bound(0, floor(spd / 16), 32767);
\r
2044 if(effectno != zcurveparticles_effectno || start != zcurveparticles_start)
\r
2046 endzcurveparticles();
\r
2047 WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
\r
2048 WriteByte(MSG_BROADCAST, TE_CSQC_ZCURVEPARTICLES);
\r
2049 WriteShort(MSG_BROADCAST, effectno);
\r
2050 WriteCoord(MSG_BROADCAST, start_x);
\r
2051 WriteCoord(MSG_BROADCAST, start_y);
\r
2052 WriteCoord(MSG_BROADCAST, start_z);
\r
2053 zcurveparticles_effectno = effectno;
\r
2054 zcurveparticles_start = start;
\r
2057 WriteShort(MSG_BROADCAST, zcurveparticles_spd);
\r
2058 WriteCoord(MSG_BROADCAST, end_x);
\r
2059 WriteCoord(MSG_BROADCAST, end_y);
\r
2060 WriteCoord(MSG_BROADCAST, end_z);
\r
2061 WriteCoord(MSG_BROADCAST, end_dz);
\r
2062 zcurveparticles_spd = spd;
\r
2065 void zcurveparticles_from_tracetoss(float effectno, vector start, vector end, vector vel)
\r
2068 vector vecxy, velxy;
\r
2070 vecxy = end - start;
\r
2075 if (vlen(velxy) < 0.000001 * fabs(vel_z))
\r
2077 endzcurveparticles();
\r
2078 trailparticles(world, effectno, start, end);
\r
2082 end_dz = vlen(vecxy) / vlen(velxy) * vel_z - (end_z - start_z);
\r
2083 zcurveparticles(effectno, start, end, end_dz, vlen(vel));
\r
2086 string GetGametype(); // g_world.qc
\r
2087 void write_recordmarker(entity pl, float tstart, float dt)
\r
2089 GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt)));
\r
2091 // also write a marker into demo files for demotc-race-record-extractor to find
\r
2094 strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))),
\r
2095 " ", ftos(tstart), " ", ftos(dt), "\n"));
\r
2098 vector shotorg_adjustfromclient(vector vecs, float y_is_right, float allowcenter)
\r
2100 switch(self.owner.cvar_cl_gunalign)
\r
2111 if(allowcenter) // 2: allow center handedness
\r
2124 if(allowcenter) // 2: allow center handedness
\r
2140 vector shotorg_adjust(vector vecs, float y_is_right, float visual)
\r
2145 if (cvar("g_shootfromeye"))
\r
2149 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2157 else if (cvar("g_shootfromcenter"))
\r
2161 vecs = shotorg_adjustfromclient(vecs, y_is_right, TRUE);
\r
2169 else if ((s = cvar_string("g_shootfromfixedorigin")) != "")
\r
2179 else if (cvar("g_shootfromclient"))
\r
2181 vecs = shotorg_adjustfromclient(vecs, y_is_right, (cvar("g_shootfromclient") >= 2));
\r
2188 void attach_sameorigin(entity e, entity to, string tag)
\r
2190 vector org, t_forward, t_left, t_up, e_forward, e_up;
\r
2191 vector org0, ang0;
\r
2197 org = e.origin - gettaginfo(to, gettagindex(to, tag));
\r
2198 tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag
\r
2199 t_forward = v_forward * tagscale;
\r
2200 t_left = v_right * -tagscale;
\r
2201 t_up = v_up * tagscale;
\r
2203 e.origin_x = org * t_forward;
\r
2204 e.origin_y = org * t_left;
\r
2205 e.origin_z = org * t_up;
\r
2207 // current forward and up directions
\r
2208 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2209 e.angles = AnglesTransform_FromVAngles(e.angles);
\r
2211 e.angles = AnglesTransform_FromAngles(e.angles);
\r
2212 fixedmakevectors(e.angles);
\r
2214 // untransform forward, up!
\r
2215 e_forward_x = v_forward * t_forward;
\r
2216 e_forward_y = v_forward * t_left;
\r
2217 e_forward_z = v_forward * t_up;
\r
2218 e_up_x = v_up * t_forward;
\r
2219 e_up_y = v_up * t_left;
\r
2220 e_up_z = v_up * t_up;
\r
2222 e.angles = fixedvectoangles2(e_forward, e_up);
\r
2223 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2224 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2226 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2228 setattachment(e, to, tag);
\r
2229 setorigin(e, e.origin);
\r
2232 void detach_sameorigin(entity e)
\r
2235 org = gettaginfo(e, 0);
\r
2236 e.angles = fixedvectoangles2(v_forward, v_up);
\r
2237 if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
\r
2238 e.angles = AnglesTransform_ToVAngles(e.angles);
\r
2240 e.angles = AnglesTransform_ToAngles(e.angles);
\r
2241 setorigin(e, org);
\r
2242 setattachment(e, world, "");
\r
2243 setorigin(e, e.origin);
\r
2246 void follow_sameorigin(entity e, entity to)
\r
2248 e.movetype = MOVETYPE_FOLLOW; // make the hole follow
\r
2249 e.aiment = to; // make the hole follow bmodel
\r
2250 e.punchangle = to.angles; // the original angles of bmodel
\r
2251 e.view_ofs = e.origin - to.origin; // relative origin
\r
2252 e.v_angle = e.angles - to.angles; // relative angles
\r
2255 void unfollow_sameorigin(entity e)
\r
2257 e.movetype = MOVETYPE_NONE;
\r
2260 entity gettaginfo_relative_ent;
\r
2261 vector gettaginfo_relative(entity e, float tag)
\r
2263 if (!gettaginfo_relative_ent)
\r
2265 gettaginfo_relative_ent = spawn();
\r
2266 gettaginfo_relative_ent.effects = EF_NODRAW;
\r
2268 gettaginfo_relative_ent.model = e.model;
\r
2269 gettaginfo_relative_ent.modelindex = e.modelindex;
\r
2270 gettaginfo_relative_ent.frame = e.frame;
\r
2271 return gettaginfo(gettaginfo_relative_ent, tag);
\r
2274 void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn)
\r
2278 if (pl.soundentity.cnt & p)
\r
2280 soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn);
\r
2281 pl.soundentity.cnt |= p;
\r
2284 void SoundEntity_StopSound(entity pl, float chan)
\r
2288 if (pl.soundentity.cnt & p)
\r
2290 stopsoundto(MSG_ALL, pl.soundentity, chan);
\r
2291 pl.soundentity.cnt &~= p;
\r
2295 void SoundEntity_Attach(entity pl)
\r
2297 pl.soundentity = spawn();
\r
2298 pl.soundentity.classname = "soundentity";
\r
2299 pl.soundentity.owner = pl;
\r
2300 setattachment(pl.soundentity, pl, "");
\r
2301 setmodel(pl.soundentity, "null");
\r
2304 void SoundEntity_Detach(entity pl)
\r
2307 for (i = 0; i <= 7; ++i)
\r
2308 SoundEntity_StopSound(pl, i);
\r
2312 float ParseCommandPlayerSlotTarget_firsttoken;
\r
2313 entity GetCommandPlayerSlotTargetFromTokenizedCommand(float tokens, float idx) // idx = start index
\r
2321 ParseCommandPlayerSlotTarget_firsttoken = -1;
\r
2325 if (substring(argv(idx), 0, 1) == "#")
\r
2327 s = substring(argv(idx), 1, -1);
\r
2335 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2336 if (s == ftos(stof(s)))
\r
2338 e = edict_num(stof(s));
\r
2339 if (e.flags & FL_CLIENT)
\r
2345 // it must be a nick name
\r
2348 ParseCommandPlayerSlotTarget_firsttoken = idx;
\r
2351 FOR_EACH_CLIENT(head)
\r
2352 if (head.netname == s)
\r
2360 s = strdecolorize(s);
\r
2362 FOR_EACH_CLIENT(head)
\r
2363 if (strdecolorize(head.netname) == s)
\r
2378 float modeleffect_SendEntity(entity to, float sf)
\r
2381 WriteByte(MSG_ENTITY, ENT_CLIENT_MODELEFFECT);
\r
2384 if(self.velocity != '0 0 0')
\r
2386 if(self.angles != '0 0 0')
\r
2388 if(self.avelocity != '0 0 0')
\r
2391 WriteByte(MSG_ENTITY, f);
\r
2392 WriteShort(MSG_ENTITY, self.modelindex);
\r
2393 WriteByte(MSG_ENTITY, self.skin);
\r
2394 WriteByte(MSG_ENTITY, self.frame);
\r
2395 WriteCoord(MSG_ENTITY, self.origin_x);
\r
2396 WriteCoord(MSG_ENTITY, self.origin_y);
\r
2397 WriteCoord(MSG_ENTITY, self.origin_z);
\r
2400 WriteCoord(MSG_ENTITY, self.velocity_x);
\r
2401 WriteCoord(MSG_ENTITY, self.velocity_y);
\r
2402 WriteCoord(MSG_ENTITY, self.velocity_z);
\r
2406 WriteCoord(MSG_ENTITY, self.angles_x);
\r
2407 WriteCoord(MSG_ENTITY, self.angles_y);
\r
2408 WriteCoord(MSG_ENTITY, self.angles_z);
\r
2412 WriteCoord(MSG_ENTITY, self.avelocity_x);
\r
2413 WriteCoord(MSG_ENTITY, self.avelocity_y);
\r
2414 WriteCoord(MSG_ENTITY, self.avelocity_z);
\r
2416 WriteShort(MSG_ENTITY, self.scale * 256.0);
\r
2417 WriteShort(MSG_ENTITY, self.scale2 * 256.0);
\r
2418 WriteByte(MSG_ENTITY, self.teleport_time * 100.0);
\r
2419 WriteByte(MSG_ENTITY, self.fade_time * 100.0);
\r
2420 WriteByte(MSG_ENTITY, self.alpha * 255.0);
\r
2425 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
2430 e.classname = "modeleffect";
\r
2436 e.avelocity = angv;
\r
2438 e.teleport_time = t1;
\r
2442 e.scale = s0 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2446 e.scale2 = s2 / max6(-e.mins_x, -e.mins_y, -e.mins_z, e.maxs_x, e.maxs_y, e.maxs_z);
\r
2449 sz = max(e.scale, e.scale2);
\r
2450 setsize(e, e.mins * sz, e.maxs * sz);
\r
2451 Net_LinkEntity(e, FALSE, 0.1, modeleffect_SendEntity);
\r
2454 void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
\r
2456 return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
\r
2459 float randombit(float bits)
\r
2461 if not(bits & (bits-1)) // this ONLY holds for powers of two!
\r
2470 for(f = 1; f <= bits; f *= 2)
\r
2479 r = (r - 1) / (n - 1);
\r
2486 float randombits(float bits, float k, float error_return)
\r
2490 while(k > 0 && bits != r)
\r
2492 r += randombit(bits - r);
\r
2501 void randombit_test(float bits, float iter)
\r
2505 print(ftos(randombit(bits)), "\n");
\r
2510 float ExponentialFalloff(float mindist, float maxdist, float halflifedist, float d)
\r
2512 if(halflifedist > 0)
\r
2513 return pow(0.5, (bound(mindist, d, maxdist) - mindist) / halflifedist);
\r
2514 else if(halflifedist < 0)
\r
2515 return pow(0.5, (bound(mindist, d, maxdist) - maxdist) / halflifedist);
\r
2524 #define cvar_string_normal cvar_string_builtin
\r
2525 #define cvar_normal cvar_builtin
\r
2527 string cvar_string_normal(string n)
\r
2529 if not(cvar_type(n) & 1)
\r
2530 backtrace(strcat("Attempt to access undefined cvar: ", n));
\r
2531 return cvar_string_builtin(n);
\r
2534 float cvar_normal(string n)
\r
2536 return stof(cvar_string_normal(n));
\r
2539 #define cvar_set_normal cvar_set_builtin
\r
2541 void defer_think()
\r
2546 self = self.owner;
\r
2547 oself.think = SUB_Remove;
\r
2548 oself.nextthink = time;
\r
2554 Execute func() after time + fdelay.
\r
2555 self when func is executed = self when defer is called
\r
2557 void defer(float fdelay, void() func)
\r
2564 e.think = defer_think;
\r
2565 e.nextthink = time + fdelay;
\r